Exemple #1
0
 def _visit(self, node: Any) -> Optional[Any]:
     if isinstance(node, (YAMLRoot, dict)) or is_YAMLROOT(node):
         if isinstance(node, YAMLRoot) or is_YAMLROOT(node):
             node = self._add_type(node)
         for k, v in list(node.items()):
             if v:
                 new_v = self._visit(v)
                 if new_v is not None:
                     node[k] = new_v
     elif isinstance(node, list):
         for i in range(0, len(node)):
             new_v = self._visit(node[i])
             if new_v is not None:
                 node[i] = new_v
     elif isinstance(node, set):
         for v in list(node):
             new_v = self._visit(v)
             if new_v is not None:
                 node.remove(v)
                 node.add(new_v)
     elif isinstance(node, ClassDefinitionName):
         return ClassDefinitionName(camelcase(node))
     elif isinstance(node, SlotDefinitionName):
         return SlotDefinitionName(underscore(node))
     elif isinstance(node, TypeDefinitionName):
         return TypeDefinitionName(underscore(node))
     elif isinstance(node, SubsetDefinitionName):
         return SubsetDefinitionName(underscore(node))
     elif isinstance(node, ElementName):
         return ClassDefinitionName(camelcase(node)) if node in self.schema.classes else \
             SlotDefinitionName(underscore(node)) if node in self.schema.slots else \
             SubsetDefinitionName(camelcase(node)) if node in self.schema.subsets else \
             TypeDefinitionName(underscore(node)) if node in self.schema.types else None
     return None
    def _link(self, obj: Optional[Element], *, after_link: str = None, use_desc: bool=False,
             add_subset: bool=True) -> str:
        """ Create a link to ref if appropriate.

        @param ref: the name or value of a class, slot, type or the name of a built in type.
        @param after_link: Text to put between link and description
        @param use_desc: True means append a description after the link if available
        @param add_subset: True means add any subset information that is available
        @return:
        """
        nl = '\n'
        if obj is None or not self.is_secondary_ref(obj.name):
            return self.bbin(obj)
        if isinstance(obj, SlotDefinition):
            link_name = ((be(obj.domain) + '➞') if obj.alias else '') + self.aliased_slot_name(obj)
            link_ref = underscore(obj.name)
        elif isinstance(obj, TypeDefinition):
            link_name = camelcase(obj.name)
            link_ref = f"types/{link_name}" if not self.no_types_dir else f"{link_name}"
        elif isinstance(obj, ClassDefinition):
            link_name = camelcase(obj.name)
            link_ref = camelcase(link_name)
        else:
            link_name = obj.name
            link_ref = link_name
        desc = self.desc_for(obj, use_desc)
        return f'[{link_name}]' \
               f'({link_ref}.{self.format})' + \
                 (f' {after_link} ' if after_link else '') + (f' - {desc.split(nl)[0]}' if desc else '')
Exemple #3
0
 def gen_references(self) -> str:
     """ Generate python type declarations for all identifiers (primary keys)
     """
     rval = []
     for cls in self._sort_classes(self.schema.classes.values()):
         if not cls.imported_from:
             pkeys = self.primary_keys_for(cls)
             if pkeys:
                 for pk in pkeys:
                     classname = camelcase(cls.name) + camelcase(
                         self.aliased_slot_name(pk))
                     # If we've got a parent slot and the range of the parent is the range of the child, the
                     # child slot is a subclass of the parent.  Otherwise, the child range has been overridden,
                     # so the inheritence chain has been broken
                     parent_pk = self.class_identifier(
                         cls.is_a) if cls.is_a else None
                     parent_pk_slot = self.schema.slots[
                         parent_pk] if parent_pk else None
                     pk_slot = self.schema.slots[pk]
                     if parent_pk_slot and (parent_pk_slot.name == pk
                                            or pk_slot.range
                                            == parent_pk_slot.range):
                         parents = self.class_identifier_path(
                             cls.is_a, False)
                     else:
                         parents = self.slot_range_path(pk_slot)
                     parent_cls = 'extended_' + parents[-1] if parents[
                         -1] in ['str', 'float', 'int'] else parents[-1]
                     rval.append(
                         f'class {classname}({parent_cls}):\n\tpass')
                     break  # We only do the first primary key
     return '\n\n\n'.join(rval)
Exemple #4
0
 def end_class(self, cls: ClassDefinition) -> None:
     tname = camelcase(cls.name)
     if self.use_inherits and cls.is_a:
         # postgresql supports inheritance
         # if you want to use plain SQL DDL then use sqlutils to unfold hierarchy
         # TODO: raise error if the target is standard SQL
         p = camelcase(cls.is_a)
         logging.error("Not supported in sqlalchemy")
Exemple #5
0
    def test_formats(self):
        self.assertEqual("ThisIsIt", camelcase("this is it"))
        self.assertEqual("ThisIsIT", camelcase("  this   is iT   "))
        self.assertEqual("IBeY", camelcase("i be y "))
        self.assertEqual("ThisIsIt", camelcase("This__is_it"))

        self.assertEqual("this_is_it", underscore(" this is it "))
        self.assertEqual("this_is_it", underscore("this   is   it"))

        self.assertEqual("thisIsIt", lcamelcase("   this   is\t  it\n"))

        self.assertEqual('abc', be('  abc\n'))
        self.assertEqual('', be(None))
        self.assertEqual('', be('   '))
Exemple #6
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     self.clswq = (WQ().add_class(camelcase(cls.name)).label(
         camelcase(cls.name)).description(be(cls.description)))
     if cls.is_a:
         self.clswq.parent(camelcase(cls.is_a))
     if cls.abstract:
         self.clswq.abstract()
     if cls.broad_mappings:
         if any(
                 str(self.namespaces.uri_for(m)) ==
                 "http://terminusdb.com/schema/system#Document"
                 for m in cls.broad_mappings):
             self.clswq.parent("Document")
     return True
Exemple #7
0
 def class_or_type_name(self, name: str) -> str:
     """
     Return the camelcase representation of clsname if it is a valid class or type.  Prepend "Unknown"
     if the name isn't valid
     """
     if name in self.schema.classes:
         return camelcase(name)
     elif name in self.schema.types:
         typ = self.schema.types[cast(TypeDefinitionName, name)]
         if typ.typeof:
             return camelcase(name)
         else:
             return typ.base
     else:
         return "Unknown_" + camelcase(name)
Exemple #8
0
 def gen_slot(self, slot: SlotDefinition) -> str:
     python_slot_name = underscore(slot.name)
     slot_uri, slot_curie = self.python_uri_for(slot.slot_uri)
     slot_model_uri, slot_model_curie = \
         self.python_uri_for(self.namespaces.uri_or_curie_for(self.schema.default_prefix, python_slot_name))
     domain = camelcase(
         slot.domain) if slot.domain and not self.schema.classes[
             slot.domain].mixin else "None"
     # Going to omit the range on keys where the domain isn't specified (for now)
     if slot.domain is None and (slot.key or slot.identifier):
         rnge = "URIRef"
     else:
         rnge, _ = self.range_cardinality(
             slot,
             self.schema.classes[slot.domain] if slot.domain else None,
             True)
     if slot.mappings:
         map_texts = [
             self.namespaces.curie_for(self.namespaces.uri_for(m),
                                       default_ok=True,
                                       pythonform=True)
             for m in slot.mappings if m != slot.slot_uri
         ]
     else:
         map_texts = []
     if map_texts:
         mappings = ', mappings = [' + ', '.join(map_texts) + ']'
     else:
         mappings = ''
     pattern = f",\n                   pattern=re.compile(r'{slot.pattern}')" if slot.pattern else ""
     return f"""slots.{python_slot_name} = Slot(uri={slot_uri}, name="{slot.name}", curie={slot_curie},
Exemple #9
0
 def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str,
                      slot: SlotDefinition) -> None:
     qual = 'repeated ' if slot.multivalued else 'optional ' if not slot.required or slot.key else ''
     slotname = lcamelcase(aliased_slot_name)
     slot_range = camelcase(slot.range)
     self.relative_slot_num += 1
     print(f"  {qual}{slotname} {slot_range} = {self.relative_slot_num}")
Exemple #10
0
 def gen_type_meta(self, typ: TypeDefinition) -> str:
     type_class_uri = self.namespaces.uri_for(typ.uri)
     if type_class_uri:
         type_python_uri = self.namespaces.curie_for(type_class_uri,
                                                     default_ok=False,
                                                     pythonform=True)
         type_class_curie = self.namespaces.curie_for(type_class_uri,
                                                      default_ok=False,
                                                      pythonform=False)
     else:
         type_python_uri = None
         type_class_curie = None
     if type_class_curie:
         type_class_curie = f'"{type_class_curie}"'
     type_class_uri = type_python_uri if type_python_uri else f'URIRef("{type_class_uri}")'
     type_model_uri = self.namespaces.uri_or_curie_for(
         self.schema.default_prefix, camelcase(typ.name))
     if ':/' in type_model_uri:
         type_model_uri = f'URIRef("{type_model_uri}")'
     else:
         ns, ln = type_model_uri.split(':', 1)
         ln_suffix = f".{ln}" if ln.isidentifier() else f'["{ln}"]'
         type_model_uri = f"{ns.upper()}{ln_suffix}"
     vars = [
         f'type_class_uri = {type_class_uri}',
         f'type_class_curie = {type_class_curie}',
         f'type_name = "{typ.name}"', f'type_model_uri = {type_model_uri}'
     ]
     return "\n\t".join(vars)
Exemple #11
0
    def gen_class_meta(self, cls: ClassDefinition) -> str:
        if not self.gen_classvars:
            return ''
        class_class_uri = self.namespaces.uri_for(cls.class_uri)
        if class_class_uri:
            cls_python_uri = self.namespaces.curie_for(class_class_uri,
                                                       default_ok=False,
                                                       pythonform=True)
            class_class_curie = self.namespaces.curie_for(class_class_uri,
                                                          default_ok=False,
                                                          pythonform=False)
        else:
            cls_python_uri = None
            class_class_curie = None
        if class_class_curie:
            class_class_curie = f'"{class_class_curie}"'
        class_class_uri = cls_python_uri if cls_python_uri else f'URIRef("{class_class_uri}")'
        class_model_uri = self.namespaces.uri_or_curie_for(
            self.schema.default_prefix or "DEFAULT_", camelcase(cls.name))
        if ':/' in class_model_uri:
            class_model_uri = f'URIRef("{class_model_uri}")'
        else:
            ns, ln = class_model_uri.split(':', 1)
            class_model_uri = f"{ns.upper()}.{ln}"

        vars = [
            f'class_class_uri: ClassVar[URIRef] = {class_class_uri}',
            f'class_class_curie: ClassVar[str] = {class_class_curie}',
            f'class_name: ClassVar[str] = "{cls.name}"',
            f'class_model_uri: ClassVar[URIRef] = {class_model_uri}'
        ]
        return "\n\t" + "\n\t".join(vars) + "\n"
Exemple #12
0
    def class_identifier_path(self, cls_or_clsname: Union[str,
                                                          ClassDefinition],
                              force_non_key: bool) -> List[str]:
        """
        Return the path closure to a class identifier if the class has a key and force_non_key is false otherwise
        return a dictionary closure.

        :param cls_or_clsname: class definition
        :param force_non_key: True means inlined even if the class has a key
        :return: path
        """
        cls = cls_or_clsname if isinstance(cls_or_clsname, ClassDefinition) \
            else self.schema.classes[ClassDefinitionName(cls_or_clsname)]

        # Determine whether the class has a key
        identifier_slot = None
        if not force_non_key:
            identifier_slot = self.class_identifier(cls)

        # No key or inlined, its closure is a dictionary
        if identifier_slot is None:
            return ['dict', self.class_or_type_name(cls.name)]

        # We're dealing with a reference
        pathname = camelcase(cls.name + ' ' +
                             self.aliased_slot_name(identifier_slot))
        if cls.is_a:
            parent_identifier_slot = self.class_identifier(cls.is_a)
            if parent_identifier_slot:
                return self.class_identifier_path(cls.is_a, False) + [pathname]
        return self.slot_range_path(identifier_slot) + [pathname]
Exemple #13
0
    def gen_enum(self, enum: EnumDefinition) -> str:
        enum_name = camelcase(enum.name)
        return f'''
class {enum_name}(EnumDefinitionImpl):
    {self.gen_enum_comment(enum)}
    {self.gen_enum_description(enum, enum_name)}
'''.strip()
Exemple #14
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     etype = 'interface' if (cls.abstract
                             or cls.mixin) and not cls.mixins else 'type'
     mixins = ', '.join([camelcase(mixin) for mixin in cls.mixins])
     print(f"{etype} {camelcase(cls.name)}" +
           (f" implements {mixins}" if mixins else ""))
     print("  {")
     return True
Exemple #15
0
 def adjust_slot(self, slot: SlotDefinition) -> None:
     if slot.range in self.schema.classes:
         slot.range = ClassDefinitionName(camelcase(slot.range))
     elif slot.range in self.schema.slots:
         slot.range = SlotDefinitionName(underscore(slot.range))
     elif slot.range in self.schema.types:
         slot.range = TypeDefinitionName(underscore(slot.range))
     slot.slot_uri = self.namespaces.uri_for(slot.slot_uri)
Exemple #16
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     if self._is_hidden(cls):
         return False
     if cls.description:
         None  ## TODO
     tname = camelcase(cls.name)
     self.columns[tname] = {}
     return True
Exemple #17
0
 def enum_identifier_path(
         self, enum_or_enumname: Union[str, EnumDefinition]) -> List[str]:
     """ Return an enum_identifier path """
     return [
         'str',
         camelcase(enum_or_enumname.name if isinstance(
             enum_or_enumname, EnumDefinition) else enum_or_enumname)
     ]
Exemple #18
0
 def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str,
                      slot: SlotDefinition) -> None:
     slotrange = camelcase(slot.range) if slot.range in self.schema.classes or slot.range in self.schema.types or \
                                          slot.range in self.schema.enums else "String"
     if slot.multivalued:
         slotrange = f"[{slotrange}]"
     if slot.required:
         slotrange = slotrange + '!'
     print(f"    {lcamelcase(aliased_slot_name)}: {slotrange}")
Exemple #19
0
    def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str, slot: SlotDefinition) -> None:
        if slot.range in self.schema.classes and slot.inlined:
            rng = f"#/definitions/{camelcase(slot.range)}"
        elif slot.range in self.schema.types:
            rng = self.schema.types[slot.range].base
        else:
            # note we assume string for non-lined complex objects
            rng = "string"

        # translate to json-schema builtins
        if rng == 'int':
            rng = 'integer'
        elif rng == 'Bool':
            rng = 'boolean'
        elif rng == 'str':
            rng = 'string'
        elif rng == 'float' or rng == 'double':
            rng = 'number'
        elif not rng.startswith('#'):
            # URIorCURIE, etc
            rng = 'string'

        if slot.inlined:
            # If inline we have to include redefined slots
            ref = JsonObj()
            ref['$ref'] = rng
            if slot.multivalued:
                prop = JsonObj(type="array", items=ref)
            else:
                prop = ref
        else:
            if slot.multivalued:
                prop = JsonObj(type="array", items={'type': rng})
            else:
                prop = JsonObj(type=rng)
        if slot.description:
            prop.description = slot.description
        if slot.required:
            self.clsobj.required.append(underscore(aliased_slot_name))

        self.clsobj.properties[underscore(aliased_slot_name)] = prop
        if self.topCls is not None and camelcase(self.topCls) == camelcase(cls.name) or \
                self.topCls is None and cls.tree_root:
            self.schemaobj.properties[underscore(aliased_slot_name)] = prop
Exemple #20
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     if cls.mixin or cls.abstract:
         return False
     self.clsobj = JsonObj(title=camelcase(cls.name),
                           type='object',
                           properties=JsonObj(),
                           required=[],
                           additionalProperties=False,
                           description=be(cls.description))
     return True
Exemple #21
0
    def gen_typedefs(self) -> str:
        """ Generate python type declarations for all defined types """
        rval = []
        for typ in self.schema.types.values():
            if not typ.imported_from:
                typname = camelcase(typ.name)
                desc = f'\n\t""" {typ.description} """' if typ.description else ''

                if typ.typeof:
                    parent_typename = camelcase(typ.typeof)
                    rval.append(
                        f'class {typname}({parent_typename}):{desc}\n\t{self.gen_type_meta(typ)}\n\n'
                    )
                else:
                    base_base = typ.base.rsplit('.')[-1]
                    rval.append(
                        f'class {typname}({base_base}):{desc}\n\t{self.gen_type_meta(typ)}\n\n'
                    )
        return '\n'.join(rval)
Exemple #22
0
    def visit_type(self, typ: TypeDefinition) -> None:
        """
        Visit a given type definition and write the following properties in Markdown,
        - Frontmatter
        - Description
        - Domain and Range constraints
        - Parents
        - Children
        - Used by

        Parameters
        ----------
        typ: linkml_model.meta.TypeDefinition
            A TypeDefinition

        """
        with open(self.dir_path(typ), 'w') as typefile:
            with redirect_stdout(typefile):
                full_path = sfx(self.namespaces._base) + (sfx(
                    typ.imported_from) if typ.imported_from else '')
                type_curie = self.namespaces.uri_or_curie_for(
                    full_path, camelcase(typ.name))
                type_uri = self.namespaces.uri_for(type_curie)

                if type_curie.startswith(
                        'https://w3id.org/biolink/vocab/linkml:types/'):
                    ref = type_curie.split('/')[-1]
                    type_uri = f"https://linkml.github.io/linkml-model/docs/types/{ref}"
                    type_curie = f"metatype:{ref}"
                elif type_uri.startswith('https://w3id.org/biolink/vocab/'):
                    ref = type_curie.split('/')[-1]
                    type_uri = f"https://w3id.org/biolink/vocab/types/{ref}"
                if typ.imported_from and 'linkml:types' in typ.imported_from:
                    parent = 'Built-in Types'
                else:
                    parent = 'Defined Types'
                self.frontmatter(
                    **{
                        'parent': parent,
                        'grand_parent': 'Types',
                        'title': type_curie,
                        'layout': 'default'
                    })
                self.element_header(typ, typ.name, type_curie, type_uri)

                print("|  |  |  |")
                print("| --- | --- | --- |")
                if typ.typeof:
                    print(
                        f"| Parent type | | {self.class_type_link(typ.typeof)} |"
                    )
                print(f"| Root (builtin) type | | **{typ.base}** |")
                if typ.repr:
                    print(f"| Representation | | {typ.repr} |")
Exemple #23
0
 def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str,
                      slot: SlotDefinition) -> None:
     #qual = 'repeated ' if slot.multivalued else 'optional ' if not slot.required or slot.key else ''
     slotname = underscore(aliased_slot_name)
     tname = camelcase(cls.name)
     slot_range = self.get_sql_range(slot)
     if slot.multivalued:
         linktable_name = f'{tname}_to_{slotname}'
         pk = self._get_primary_key(cls)
         if pk is None:
             if self.inject_primary_keys:
                 pk = 'id'
                 self.columns[camelcase(cls.name)][pk] = Column(
                     pk, Text(), primary_key=True)
             else:
                 raise Exception(
                     f'Cannot have multivalued on cols with no PK: {tname} . {slotname}'
                 )
         ref = f'ref_{tname}'
         linkrange = None
         if isinstance(slot_range, ForeignKey):
             linkrange = Text()
         else:
             linkrange = slot_range
         linktable_slot = slotname
         if slot.singular_name is not None:
             linktable_slot = underscore(slot.singular_name)
         self.columns[linktable_name] = {
             linktable_slot: Column(linktable_slot,
                                    linkrange,
                                    nullable=False),
             ref: Column(ref, ForeignKey(f'{tname}.{pk}'), nullable=False)
         }
     is_pk = slot.identifier
     col = Column(slotname,
                  slot_range,
                  primary_key=is_pk,
                  nullable=not slot.required)
     self.columns[tname][slotname] = col
Exemple #24
0
 def _class_or_type_uri(self,
                        item: Union[TypeDefinition, ClassDefinition,
                                    ElementName],
                        suffix: Optional[str] = '') -> URIorCURIE:
     # TODO: enums - figure this out
     if isinstance(item, (TypeDefinition, ClassDefinition, EnumDefinition)):
         cls_or_type = item
     else:
         cls_or_type = self.class_or_type_for(item)
     return self.namespaces.uri_for(
         self.namespaces.uri_or_curie_for(
             self.schema_defaults[cls_or_type.from_schema],
             camelcase(cls_or_type.name) + suffix))
Exemple #25
0
    def visit_schema(self,
                     classes: Set[ClassDefinitionName] = None,
                     directory: Optional[str] = None,
                     load_image: bool = True,
                     **_) -> None:
        if directory:
            os.makedirs(directory, exist_ok=True)
        if classes is not None:
            for cls in classes:
                if cls not in self.schema.classes:
                    raise ValueError(f"Unknown class name: {cls}")
        self.box_generated = set()
        self.associations_generated = set()
        self.focus_classes = classes
        if classes:
            self.gen_classes = self.neighborhood(
                list(classes)).classrefs.union(classes)
        else:
            self.gen_classes = self.synopsis.roots.classrefs
        self.referenced = self.gen_classes
        self.generated = set()
        yumlclassdef: List[str] = []
        while self.referenced.difference(self.generated):
            cn = sorted(list(self.referenced.difference(self.generated)),
                        reverse=True)[0]
            self.generated.add(cn)
            assocs = self.class_associations(ClassDefinitionName(cn), cn
                                             in self.referenced)
            if assocs:
                yumlclassdef.append(assocs)
            else:
                yumlclassdef.append(self.class_box(ClassDefinitionName(cn)))

        yuml_url = str(YUML) + ','.join(yumlclassdef) + \
                   (('.' + self.format) if self.format not in ('yuml', 'svg') else '')
        file_suffix = '.svg' if self.format == 'yuml' else '.' + self.format
        if directory:
            self.output_file_name = os.path.join(
                directory,
                camelcase(sorted(classes)[0] if classes else self.schema.name)
                + file_suffix)
            if load_image:
                resp = requests.get(yuml_url, stream=True)
                if resp.ok:
                    with open(self.output_file_name, 'wb') as f:
                        for chunk in resp.iter_content(chunk_size=2048):
                            f.write(chunk)
                else:
                    self.logger.error(f"{resp.reason} accessing {yuml_url}")
        else:
            print(str(YUML) + ','.join(yumlclassdef), end='')
Exemple #26
0
    def visit_class(self, cls: ClassDefinition) -> bool:
        class_def = {}
        cn = camelcase(cls.name)
        self.add_mappings(cls)
        cls_prefix = self.namespaces.prefix_for(cls.class_uri)
        if not self.default_ns or not cls_prefix or cls_prefix != self.default_ns:
            class_def['@id'] = cls.class_uri
            if cls_prefix:
                self.add_prefix(cls_prefix)
        if class_def:
            self.slot_class_maps[cn] = class_def

        # We don't bother to visit class slots - just all slots
        return False
Exemple #27
0
def set_from_schema(schema: SchemaDefinition) -> None:
    for t in [
            schema.subsets, schema.classes, schema.slots, schema.types,
            schema.enums
    ]:
        for k in t.keys():
            t[k].from_schema = schema.id
            if isinstance(t[k], SlotDefinition):
                fragment = underscore(t[k].name)
            else:
                fragment = camelcase(t[k].name)
            if schema.default_prefix in schema.prefixes:
                ns = schema.prefixes[schema.default_prefix].prefix_reference
            else:
                ns = str(URIRef(schema.id) + "/")
            t[k].definition_uri = f'{ns}{fragment}'
Exemple #28
0
 def visit_type(self, typ: TypeDefinition) -> None:
     type_uri = self._type_uri(typ.name)
     self.graph.add((type_uri, RDF.type, OWL.Class))
     self.graph.add((type_uri, RDF.type,
                     self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][
                         camelcase('type definition')]))
     self._add_element_properties(type_uri, typ)
     if typ.typeof:
         self.graph.add(
             (type_uri, RDFS.subClassOf, self._type_uri(typ.typeof)))
     else:
         restr = BNode()
         self.graph.add((restr, RDF.type, OWL.Restriction))
         self.graph.add((restr, OWL.qualifiedCardinality, Literal(1)))
         self.graph.add((restr, OWL.onProperty, self.top_value_uri))
         self.graph.add(
             (restr, OWL.onDataRange, self.namespaces.uri_for(typ.uri)))
         self.graph.add((type_uri, RDFS.subClassOf, restr))
Exemple #29
0
    def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str,
                         slot: SlotDefinition) -> None:
        if slot.range in self.schema.classes:
            rng = camelcase(slot.range)
        elif slot.range in self.schema.types:
            # XXX Why does `linkml.utils.metamodelcore.Identifier` subclass `str`??
            rng = str(self.schema.types[slot.range].uri)
        else:
            rng = "xsd:string"

        name = (f"{cls.name} {aliased_slot_name}"
                if slot.is_usage_slot else aliased_slot_name)

        # translate to terminusdb xsd builtins:
        if rng == "xsd:int":
            rng = "xsd:integer"
        elif rng == "xsd:float":
            rng = "xsd:double"
        elif rng == "xsd:language":
            rng = "xsd:string"

        if rng not in XSD_Ok and slot.range not in self.schema.classes:
            raise Exception(
                f"slot range for {name} must be schema class or supported xsd type. "
                f"Range {rng} is of type {type(rng)}.")

        self.clswq.property(underscore(name),
                            rng,
                            label=name,
                            description=slot.description)
        if not slot.multivalued:
            self.clswq.max(1)
        if slot.required:
            self.clswq.min(1)
        if slot.is_a:
            self.raw_additions.append(WQ().add_quad(
                underscore(name),
                "rdfs:subPropertyOf",
                self.clswq.iri(underscore(slot.is_a)),
                "inference/main",
            ))
Exemple #30
0
    def visit_slot(self, slot_name: str, slot: SlotDefinition) -> None:
        """ Add a slot definition per slot

        @param slot_name:
        @param slot:
        @return:
        """
        # Note: We use the raw name in OWL and add a subProperty arc
        slot_uri = self._prop_uri(slot.name)
        self._add_element_properties(slot_uri, slot)
        # Inherited slots are object or data properties
        # All others are annotation properties
        self.graph.add(
            (slot_uri, RDF.type, OWL.ObjectProperty if
             self.is_slot_object_property(slot) else OWL.AnnotationProperty))
        self.graph.add((slot_uri, RDF.type,
                        self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][
                            camelcase('slot definition')]))
        self.graph.add((slot_uri, RDFS.range, self._range_uri(slot)))
        if slot.domain:
            self.graph.add(
                (slot_uri, RDFS.domain, self._class_uri(slot.domain)))
        if slot.inverse:
            self.graph.add(
                (slot_uri, OWL.inverseOf, self._prop_uri(slot.inverse)))
        if slot.symmetric:
            self.graph.add((slot_uri, RDF.type, OWL.SymmetricProperty))

        # Parent slots
        if slot.is_a:
            self.graph.add(
                (slot_uri, RDFS.subPropertyOf, self._prop_uri(slot.is_a)))
        for mixin in slot.mixins:
            self.graph.add(
                (slot_uri, RDFS.subPropertyOf, self._prop_uri(mixin)))
        if slot.name in self.synopsis.applytorefs:
            for appl in self.synopsis.applytorefs[slot.name].slotrefs:
                self.graph.add(
                    (slot_uri, RDFS.subClassOf, self._prop_uri(appl)))