def parse_schema(
        self,
        schema: Dict,
        source_json_file: str,
        merged_schema: List[Dict],
        merged_prefixes: List[str],
        lenient_prefix=False,
        merged_entry_tree: Optional[EntryTree] = None,
    ):
        r"""Generates ontology code for a parsed schema extracted from a
        json config. Appends entry code to the corresponding module. Creates a
        new module file if module is generated for the first time.

        Args:
            schema: Ontology dictionary extracted from a json config.
            source_json_file: Path of the source json file.
            merged_schema: The merged schema is used to remember all
                definitions during parsing.
            merged_prefixes: To remember all prefixes encountered during
                parsing.
            lenient_prefix: Whether to remove the constraint on the prefix set.
            merged_entry_tree: an EntryTree type object and if it's not`None`
                then after running this function, all the entries from
                ontology specification file would be parsed into a tree
                structure with parent and children entries to represent
                the relationship.
        Returns:
            Modules to be imported by dependencies of the current ontology.
        """
        entry_definitions: List[Dict] = schema[SchemaKeywords.definitions]
        merged_schema.extend(entry_definitions)

        if SchemaKeywords.prefixes in schema:
            merged_prefixes.extend(schema[SchemaKeywords.prefixes])

        allowed_packages = set(
            schema.get(SchemaKeywords.prefixes, []) + [DEFAULT_PREFIX])
        sorted_prefixes = analyze_packages(allowed_packages)

        file_desc = file_header(
            schema.get(SchemaKeywords.description, ""),
            schema.get(SchemaKeywords.ontology_name, ""),
        )

        for definition in entry_definitions:
            raw_entry_name = definition[SchemaKeywords.entry_name]
            validate_entry(raw_entry_name, sorted_prefixes, lenient_prefix)

            if raw_entry_name in self.allowed_types_tree:
                warnings.warn(
                    f"Class {raw_entry_name} already present in the "
                    f"ontology, will be overridden.",
                    DuplicateEntriesWarning,
                )
            self.allowed_types_tree[raw_entry_name] = set()

            # Add the entry definition to the import managers.
            # This time adding to the root manager so everyone can access it
            # if needed, but they will only appear in the import list when
            # requested.
            # Entry class should be added to the imports before the attributes
            # to be able to used as the attribute type for the same entry.
            self.import_managers.root.add_object_to_import(raw_entry_name)

            # Get various parts of the entry name.
            en = EntryName(raw_entry_name)
            entry_item, properties = self.parse_entry(en, definition)

            # Add it as a defining object.
            self.import_managers.get(
                en.module_name).add_defining_objects(raw_entry_name)

            # Get or set module writer only if the ontology to be generated
            # is not already installed.
            if source_json_file not in self.exclude_from_writing:
                module_writer = self.module_writers.get(en.module_name)
                module_writer.set_description(file_desc)
                module_writer.source_file = source_json_file
                # Add entry item to the writer.
                module_writer.add_entry(en, entry_item)

            # Adding entry attributes to the allowed types for validation.
            for property_name in properties:
                # Check if the name is allowed.
                if not property_name.isidentifier():
                    raise InvalidIdentifierException(
                        f"The property name: {property_name} is not a valid "
                        f"python identifier.")

                if property_name in self.allowed_types_tree[en.class_name]:
                    warnings.warn(
                        f"Attribute type for the entry {en.class_name} "
                        f"and the attribute {property_name} already present in "
                        f"the ontology, will be overridden",
                        DuplicatedAttributesWarning,
                    )
                self.allowed_types_tree[en.class_name].add(property_name)
            # populate the entry tree based on information
            if merged_entry_tree is not None:
                curr_entry_name = en.class_name
                parent_entry_name = definition["parent_entry"]
                curr_entry_attributes = self.allowed_types_tree[en.class_name]
                merged_entry_tree.add_node(curr_entry_name, parent_entry_name,
                                           curr_entry_attributes)
Example #2
0
    def parse_schema(self, schema: Dict, source_json_file: str,
                     merged_schema: List[Dict]):
        r""" Generates ontology code for a parsed schema extracted from a
        json config. Appends entry code to the corresponding module. Creates a
        new module file if module is generated for the first time.

        Args:
            schema: Ontology dictionary extracted from a json config.
            source_json_file: Path of the source json file.
            merged_schema: The merged schema is used to remember all
                definitions during parsing.
        Returns:
            Modules to be imported by dependencies of the current ontology.
        """
        entry_definitions: List[Dict] = schema[SchemaKeywords.definitions]
        merged_schema.extend(entry_definitions)

        allowed_packages = set(
            schema.get(SchemaKeywords.prefixes, []) + [DEFAULT_PREFIX])
        sorted_prefixes = analyze_packages(allowed_packages)

        file_desc = file_header(schema.get(SchemaKeywords.description, ""),
                                schema.get(SchemaKeywords.ontology_name, ""))

        for definition in entry_definitions:
            raw_entry_name = definition[SchemaKeywords.entry_name]
            validate_entry(raw_entry_name, sorted_prefixes)

            if raw_entry_name in self.allowed_types_tree:
                warnings.warn(
                    f"Class {raw_entry_name} already present in the "
                    f"ontology, will be overridden.", DuplicateEntriesWarning)
            self.allowed_types_tree[raw_entry_name] = set()

            # Add the entry definition to the import managers.
            # This time adding to the root manager so everyone can access it
            # if needed, but they will only appear in the import list when
            # requested.
            # Entry class should be added to the imports before the attributes
            # to be able to used as the attribute type for the same entry.
            self.import_managers.root.add_object_to_import(raw_entry_name)

            # Get various parts of the entry name.
            en = EntryName(raw_entry_name)
            entry_item, properties = self.parse_entry(en, definition)

            # Add it as a defining object.
            self.import_managers.get(
                en.module_name).add_defining_objects(raw_entry_name)

            # Get or set module writer only if the ontology to be generated
            # is not already installed.
            if source_json_file not in self.exclude_from_writing:
                module_writer = self.module_writers.get(en.module_name)
                module_writer.set_description(file_desc)
                module_writer.source_file = source_json_file
                # Add entry item to the writer.
                module_writer.add_entry(en, entry_item)

            # Adding entry attributes to the allowed types for validation.
            for property_name in properties:
                if property_name in self.allowed_types_tree[en.class_name]:
                    warnings.warn(
                        f"Attribute type for the entry {en.class_name} "
                        f"and the attribute {property_name} already present in "
                        f"the ontology, will be overridden",
                        DuplicatedAttributesWarning)
                self.allowed_types_tree[en.class_name].add(property_name)