Exemple #1
0
 def _visit(self, node: Any) -> Optional[Any]:
     if isinstance(node, (YAMLRoot, dict)):
         if isinstance(node, YAMLRoot):
             node = node.__dict__
         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, ElementName):
         return ClassDefinitionName(camelcase(node)) if node in self.schema.classes else \
             SlotDefinitionName(underscore(node)) if node in self.schema.slots else \
             TypeDefinitionName(underscore(node)) if node in self.schema.types else \
             builtin_uri(str(node)) if str(node) in builtin_names else None
     elif str(node) in builtin_names:
         return builtin_uri(str(node))
     return None
Exemple #2
0
 def range_cardinality(self, range_type: str, slot: SlotDefinition, cls: ClassDefinition) \
         -> Tuple[str, Optional[str]]:
     if slot.multivalued:
         if slot.range in self.schema.classes:
             slot_range_cls = self.schema.classes[slot.range]
             pkeys = self.primary_keys_for(slot_range_cls)
             if pkeys:
                 pkey = camelcase(slot.range) + camelcase(pkeys[0])
                 non_keys = set(
                     self.all_slots_for(slot_range_cls)).difference(
                         set(pkeys))
                 if len(non_keys) == 1:
                     raw_range_type = self.range_type_name(
                         self.schema.slots[non_keys.pop()], cls.name)
                 else:
                     raw_range_type = "dict"
             else:
                 raw_range_type = "dict"
         else:
             pkeys = None
             pkey = 'str'
         range_signature = f"Union[{raw_range_type}, {range_type}]" \
             if slot.inlined and slot.range is not None and slot.range not in builtin_names else range_type
         return (f'List[{range_signature}]', 'empty_list()') if not slot.inlined or not pkeys \
             else (f'Dict[{pkey}, {range_signature}]', 'empty_dict()')
     elif slot.primary_key or slot.identifier or slot.required:
         return range_type, 'None' if cls.is_a else None
     elif range_type == 'bool':
         return 'bool', 'False'
     else:
         return f'Optional[{range_type}]', 'None'
Exemple #3
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     etype = 'interface' if cls.abstract or cls.mixin else 'type'
     mixins = ', '.join([camelcase(mixin) for mixin in cls.mixins])
     print(f"{camelcase(cls.name)} {etype}" +
           (f"implements {mixins}" if mixins else ""))
     print("  {")
     return True
Exemple #4
0
    def _default(self, obj):
        """ JSON serializer callback.
        1) Filter out empty values (None, {}, [] and False) and mangle the names
        2) Add ID entries for dictionary entries

        :param obj: YAMLRoot object to serialize
        :return: Serialized version of obj
        """
        from metamodel.metamodel import ClassDefinition, SlotDefinition, TypeDefinition

        if isinstance(obj, JsonObj):
            rval = dict()
            for k, v in obj.__dict__.items():
                if not k.startswith('_') and v is not None and (
                        not isinstance(v, (dict, list, bool)) or v):
                    if isinstance(v, dict):
                        itemslist = []
                        for vk, vv in v.items():
                            if isinstance(vv, ClassDefinition):
                                vv['@id'] = camelcase(vk)
                            elif isinstance(vv,
                                            (SlotDefinition, TypeDefinition)):
                                if k != 'slot_usage':
                                    vv['@id'] = underscore(vk)
                            itemslist.append(vv)
                        rval[k] = itemslist
                    else:
                        rval[k] = v
            return rval
        else:
            return super()._default(obj)
Exemple #5
0
 def visit_class(self, cls: ClassDefinition) -> bool:
     if cls.abstract:
         return False
     self.clsobj = JsonObj(title=camelcase(cls.name),
                           type='object',
                           properties=JsonObj(),
                           description=be(cls.description))
     return True
 def obj_name(self, obj: Union[str, Element]) -> str:
     """ Return the formatted name used for the supplied definition """
     if isinstance(obj, str):
         obj = self.obj_for(obj)
     if isinstance(obj, SlotDefinition):
         return underscore(self.aliased_slot_name(obj))
     else:
         return camelcase(obj if isinstance(obj, str) else obj.name)
Exemple #7
0
    def gen_references(self) -> str:
        """ Generate python type declarations for all identifiers (primary keys)

        """
        rval = []
        for cls in self.schema.classes.values():
            pkeys = self.primary_keys_for(cls)
            for pk in pkeys:
                pk_slot = self.schema.slots[pk]
                classname = camelcase(cls.name) + camelcase(pk)
                if cls.is_a and getattr(self.schema.classes[cls.is_a], pk,
                                        None):
                    parent = self.range_type_name(pk_slot, cls.is_a)
                else:
                    parent = self.python_name_for(pk_slot.range)
                rval.append(f'class {classname}({parent}):\n\tpass')
        return '\n\n\n'.join(rval)
 def test_idempotent(self):
     txt = "this is it"
     self.assertEqual(camelcase(txt), camelcase(camelcase(txt)))
     self.assertEqual("MicroRNA", camelcase("microRNA"))
     self.assertEqual("SellTheHouseNOW", camelcase("sell  the\thouseNOW"))
     self.assertEqual("X", camelcase("x"))
     self.assertEqual("X", camelcase("   x   "))
Exemple #9
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 else "String"
     if slot.multivalued:
         slotrange = f"[{slotrange}]"
     if slot.required or slot.primary_key:
         slotrange = slotrange + '!'
     print(f"    {lcamelcase(aliased_slot_name)}: {slotrange}")
    def visit_class(self, cls: ClassDefinition) -> bool:
        class_def = {}
        cn = camelcase(cls.name)
        self.add_mappings(cls, class_def)
        if class_def:
            self.slot_class_maps[cn] = class_def

        # We don't bother to visit class slots - just all slots
        return False
Exemple #11
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))
     elif slot.range in (Builtin.uri, Builtin.anytype):
         slot.range = '@id'
     elif slot.range in builtin_names and builtin_names[slot.range] not in (Builtin.anytype, Builtin.uri):
         slot.range = builtin_uri(slot.range)
Exemple #12
0
    def range_type_name(self, slot: SlotDefinition,
                        containing_class_name: ClassDefinitionName) -> str:
        """ Generate the type name for the slot """
        if slot.primary_key or slot.identifier:
            return self.python_name_for(containing_class_name) + camelcase(
                slot.name)

        if slot.range in self.schema.classes and not slot.inlined:
            class_key = self.key_name_for(cast(ClassDefinitionName,
                                               slot.range))
            if class_key:
                return class_key
        return self.python_name_for(slot.range)
Exemple #13
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)
        for cls in classes:
            if cls not in self.schema.classes:
                raise ValueError("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)

        yuml_url = str(YUML) + ', '.join(yumlclassdef) + \
                   (('.' + self.format) if self.format not in ('yuml', 'png') else '')
        file_suffix = '.png' if self.format == 'yuml' else '.' + self.format
        if directory:
            self.output_file_name = os.path.join(
                directory,
                camelcase(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:
            print(str(YUML) + ', '.join(yumlclassdef), end='')
Exemple #14
0
    def class_box(self, cn: ClassDefinitionName) -> str:
        """ Generate a box for the class.  Populate its interior only if (a) it hasn't previously been generated and
        (b) it appears in the gen_classes list

        @param cn:
        @param inherited:
        @return:
        """
        slot_defs: List[str] = []
        if cn not in self.box_generated and (not self.focus_classes
                                             or cn in self.focus_classes):
            cls = self.schema.classes[cn]
            for slotname in self.filtered_cls_slots(cn, all_slots=True):
                slot = self.schema.slots[slotname]
                if not slot.range or slot.range in builtin_names or slot.range in self.schema.types:
                    mod = self.prop_modifier(cls, slot)
                    slot_defs.append(
                        underscore(self.aliased_slot_name(slot)) + mod + ':' +
                        underscore(slot.range) + self.cardinality(slot))
            self.box_generated.add(cn)
        self.referenced.add(cn)
        return '[' + camelcase(cn) + ('|' + ';'.join(slot_defs)
                                      if slot_defs else '') + ']'
Exemple #15
0
    def visit_class(self, cls: ClassDefinition) -> bool:
        if self.gen_classes and cls.name not in self.gen_classes:
            return False
        with open(self.dir_path(cls), 'w') as clsfile:
            with redirect_stdout(clsfile):
                self.frontmatter(f"Class: {cls.name}")
                self.para(be(cls.description))

                cls_uri = BIOENTITY[camelcase(cls.name)]
                print(f'URI: [{cls_uri}]({cls_uri})')
                print()
                if self.image_directory:
                    yg = YumlGenerator(self.schema)
                    yg.serialize(classes=[cls.name],
                                 directory=self.image_directory,
                                 load_image=not self.noimages)
                    img_url = os.path.join(
                        'images', os.path.basename(yg.output_file_name))
                else:
                    img_url = YumlGenerator(self.schema).serialize(classes=[cls.name])\
                        .replace('[', '\\[').replace('?', '%3F').replace(' ', '%20')

                print(f'![img]({img_url})')
                self.mappings(cls)

                self.header(2, 'Inheritance')
                if cls.is_a is not None:
                    self.bullet(f' is_a: {self.link(cls.is_a, use_desc=True)}')
                for mixin in cls.mixins:
                    self.bullet(f' mixin: {self.link(mixin, use_desc=True)}')

                self.header(2, 'Children')
                if cls.name in self.synopsis.isarefs:
                    for child in sorted(
                            self.synopsis.isarefs[cls.name].classrefs):
                        self.bullet(f'{self.link(child, use_desc=True)}')
                if cls.name in self.synopsis.mixinrefs:
                    for mixin in sorted(
                            self.synopsis.mixinrefs[cls.name].classrefs):
                        self.bullet(
                            f'{self.link(mixin, use_desc=True, after_link="(mixin)")}'
                        )
                if cls.name in self.synopsis.classrefs:
                    self.header(2, 'Used in')
                    for sn in sorted(
                            self.synopsis.classrefs[cls.name].slotrefs):
                        slot = self.schema.slots[sn]
                        if slot.range == cls.name:
                            self.bullet(
                                f' class: **{self.link(slot.domain)}** '
                                f'*{self.link(slot.name, add_subset=False)}* **{self.link(cls.name)}**'
                            )

                self.header(2, 'Fields')
                for sn in sorted(cls.slots):
                    self.slot_field(cls, self.schema.slots[sn])

                for slot in sorted(self.all_slots(cls), key=lambda s: s.name):
                    if slot.name not in cls.slots:
                        self.slot_field(cls, slot)

        return True
Exemple #16
0
 def class_uri(cn: ClassDefinitionName) -> URIRef:
     return BIOENTITY[camelcase(cn)]
 def _shapeIRI(name: ClassDefinitionName) -> IRIREF:
     return IRIREF(BIOENTITY[camelcase(name)])
Exemple #18
0
 def end_class(self, cls: ClassDefinition) -> None:
     self.schemaobj.properties[camelcase(cls.name)] = self.clsobj
Exemple #19
0
 def key_name_for(self, class_name: ClassDefinitionName) -> Optional[str]:
     for slot_name in self.primary_keys_for(
             self.schema.classes[class_name]):
         return self.python_name_for(class_name) + camelcase(slot_name)
     return None
Exemple #20
0
 def python_class_name() -> str:
     return camelcase(name)
Exemple #21
0
 def python_type_name() -> str:
     return camelcase(name)