Ejemplo n.º 1
0
 def test_domain_slots(self):
     """ has_phenotype shouldn't appear in the UML graph """
     yuml = YumlGenerator(env.input_path('issue_12.yaml')).serialize()
     self.assertEqual('http://yuml.me/diagram/nofunky;dir:TB/class/[BiologicalEntity]++- '
                      'required thing 0..1>[PhenotypicFeature],[BiologicalEntity]', yuml)
     resp = requests.get(yuml)
     self.assertTrue(resp.ok)
Ejemplo n.º 2
0
 def test_prefix(self):
     env.generate_single_file(
         'issue112.yuml',
         lambda: YumlGenerator(env.input_path('issue_112.yaml')).serialize(
         ),
         value_is_returned=True)
     with open(env.expected_path('issue112.yuml')) as f:
         url = f.read()
     resp = requests.get(url)
     self.assertTrue(resp.ok)
Ejemplo n.º 3
0
    def visit_class(self, cls: ClassDefinition) -> bool:
        """
        Visit a given class definition and write the following properties in Markdown,
        - Frontmatter
        - Mappings
        - Description
        - UML
        - Identifier prefixes
        - Parents
        - Uses Mixins
        - Children
        - Mixin for
        - Referenced by class
        - Attributes
        - Domain constraints for slots

        Parameters
        ----------
        cls: linkml_runtime.linkml_model.meta.ClassDefinition
            A ClassDefinition

        Returns
        -------
        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):
                class_curi = self.namespaces.uri_or_curie_for(
                    self.namespaces._base, camelcase(cls.name))
                class_uri = self.namespaces.uri_for(class_curi)
                ancs = self.ancestors(cls)
                if 'named thing' in ancs:
                    parent = 'Entities'
                    grand_parent = 'Classes'
                elif 'association' in ancs:
                    parent = 'Associations'
                    grand_parent = 'Classes'
                elif cls.mixin:
                    parent = 'Class Mixins'
                    grand_parent = 'Classes'
                else:
                    parent = 'Other Classes'
                    grand_parent = 'Classes'
                self.frontmatter(
                    **{
                        'parent': parent,
                        'title': class_curi,
                        'grand_parent': grand_parent,
                        'layout': 'default'
                    })
                self.element_header(cls, cls.name, class_curi, class_uri)
                for m in cls.mappings:
                    self.badges(m, 'mapping-label')

                if self.image_directory:
                    yg = YumlGenerator(self)
                    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:
                    yg = YumlGenerator(self)
                    img_url = yg.serialize(classes=[cls.name])

                img_url = img_url.replace(' ', '%20')
                img_url = img_url.replace('<', '%3C')
                img_url = img_url.replace('^', '%5E')
                img_url = img_url.replace('>', '%3E')
                img_url = img_url.replace('|', '%7C')
                img_url = img_url.replace('*', '%2A')
                img_url = img_url.replace('&#124;', '%7C')

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

                if cls.id_prefixes:
                    self.header(2, 'Identifier prefixes')
                    for p in cls.id_prefixes:
                        self.bullet(f'{p}')

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

                if cls.name in self.synopsis.isarefs:
                    self.header(2, 'Children')
                    for child in sorted(
                            self.synopsis.isarefs[cls.name].classrefs):
                        self.bullet(f'{self.class_link(child, use_desc=True)}')

                if cls.name in self.synopsis.mixinrefs:
                    self.header(2, 'Mixin for')
                    for mixin in sorted(
                            self.synopsis.mixinrefs[cls.name].classrefs):
                        self.bullet(
                            f'{self.class_link(mixin, use_desc=True, after_link="(mixin)")}'
                        )

                if cls.name in self.synopsis.classrefs:
                    self.header(2, 'Referenced by class')
                    for sn in sorted(
                            self.synopsis.classrefs[cls.name].slotrefs):
                        slot = self.schema.slots[sn]
                        if slot.range == cls.name:
                            if slot.alias and slot.usage_slot_name:
                                original_slot = self.schema.slots[
                                    slot.usage_slot_name]
                            else:
                                original_slot = slot
                            self.bullet(
                                f' **{self.class_link(slot.domain)}** '
                                f'*{self.slot_link(original_slot, add_subset=False)}*{self.predicate_cardinality(slot)}  '
                                f'**{self.class_type_link(slot.range)}**')

                self.header(2, 'Attributes')
                own_slots = [
                    slot for slot in
                    [self.schema.slots[sn] for sn in sorted(cls.slots)]
                    if slot.owner == cls.name
                ]
                if own_slots:
                    self.header(3, 'Own')
                    for slot in own_slots:
                        if slot.alias and slot.usage_slot_name:
                            slot = self.schema.slots[slot.usage_slot_name]
                        self.slot_field(cls, slot)

                for slot_owner in sorted({
                        slot.owner
                        for slot in
                    [self.schema.slots[sn] for sn in cls.slots]
                        if slot.owner != slot.name and slot.owner != cls.name
                }):
                    self.header(3, "Inherited from " + slot_owner + ':')
                    for owner_slot_name in self.schema.classes[
                            slot_owner].slots:
                        owner_slot = self.schema.slots[owner_slot_name]
                        if owner_slot.owner == slot_owner:
                            if owner_slot.alias and owner_slot.usage_slot_name:
                                owner_slot = self.schema.slots[
                                    owner_slot.usage_slot_name]
                            self.slot_field(cls, owner_slot)

                domain_for_slots = [
                    slot for slot in
                    [self.schema.slots[sn] for sn in sorted(cls.slots)]
                    if slot.domain == cls.name
                ]
                if domain_for_slots:
                    self.header(3, 'Domain for slot:')
                    for slot in domain_for_slots:
                        if slot.alias and slot.usage_slot_name:
                            slot = self.schema.slots[slot.usage_slot_name]
                        self.slot_field(cls, slot)

                self.element_properties(cls)

        return True
Ejemplo n.º 4
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.exist_warning(self.dir_path(cls)), 'w') as clsfile:
            with redirect_stdout(clsfile):
                class_curi = self.namespaces.uri_or_curie_for(self.namespaces._base, camelcase(cls.name))
                class_uri = self.namespaces.uri_for(class_curi)
                self.element_header(cls, cls.name, class_curi, class_uri)
                print()
                if self.image_directory:
                    yg = YumlGenerator(self)
                    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:
                    yg = YumlGenerator(self)
                    img_url = yg.serialize(classes=[cls.name])\
                        .replace('?', '%3F').replace(' ', '%20').replace('|', '&#124;')

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

                if cls.id_prefixes:
                    self.header(2, 'Identifier prefixes')
                    for p in cls.id_prefixes:
                        self.bullet(f'{p}')

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

                if cls.name in self.synopsis.isarefs:
                    self.header(2, 'Children')
                    for child in sorted(self.synopsis.isarefs[cls.name].classrefs):
                        self.bullet(f'{self.class_link(child, use_desc=True)}')

                if cls.name in self.synopsis.mixinrefs:
                    self.header(2, 'Mixin for')
                    for mixin in sorted(self.synopsis.mixinrefs[cls.name].classrefs):
                        self.bullet(f'{self.class_link(mixin, use_desc=True, after_link="(mixin)")}')

                if cls.name in self.synopsis.classrefs:
                    self.header(2, 'Referenced by class')
                    for sn in sorted(self.synopsis.classrefs[cls.name].slotrefs):
                        slot = self.schema.slots[sn]
                        if slot.range == cls.name:
                            self.bullet(f' **{self.class_link(slot.domain)}** '
                                        f'*{self.slot_link(slot, add_subset=False)}*{self.predicate_cardinality(slot)}  '
                                        f'**{self.class_type_link(slot.range)}**')

                self.header(2, 'Attributes')

                # List all of the slots that directly belong to the class
                slot_list = [slot for slot in [self.schema.slots[sn] for sn in sorted(cls.slots)]]
                own_slots = [slot for slot in slot_list if cls.name in slot.domain_of]
                if own_slots:
                    self.header(3, 'Own')
                    for slot in own_slots:
                        self.slot_field(cls, slot)
                        slot_list.remove(slot)

                # List all of the inherited slots
                ancestors = set(self.ancestors(cls))
                inherited_slots = [slot for slot in slot_list if set(slot.domain_of).intersection(ancestors)]
                if inherited_slots:
                    self.header(3, "Inherited from " + cls.is_a + ':')
                    for inherited_slot in inherited_slots:
                        self.slot_field(cls, inherited_slot)
                        slot_list.remove(inherited_slot)

                # List all of the slots acquired through mixing
                mixed_in_classes = set()
                for mixin in cls.mixins:
                    mixed_in_classes.add(mixin)
                    mixed_in_classes.update(set(self.ancestors(self.schema.classes[mixin])))
                for slot in slot_list:
                    mixers = set(slot.domain_of).intersection(mixed_in_classes)
                    for mixer in mixers:
                        self.header(3, "Mixed in from " + mixer + ':')
                        self.slot_field(cls, slot)

                self.element_properties(cls)

        return False