Пример #1
0
    def parse_list(
            self, manager: ImportManager, schema: Dict, entry_name: EntryName,
            att_name: str, att_type: str, desc: str) -> ListProperty:
        if SchemaKeywords.element_type not in schema:
            raise TypeNotDeclaredException(
                f"Item type for the attribute {att_name} of the entry "
                f"[{entry_name.class_name}] not declared. This attribute is "
                f"a composite type: {att_type}, it should have a "
                f"{SchemaKeywords.element_type}.")

        item_type = schema[SchemaKeywords.element_type]
        if is_composite_type(item_type):
            # Case of nested.
            raise UnsupportedTypeException(
                f"Item type {item_type} for entry {entry_name.name}'s "
                f"attribute {att_name} is a composite type, we do not support "
                f"nested composite type.")

        if not manager.is_known_name(item_type):
            # Case of unknown.
            raise TypeNotDeclaredException(
                f"Item type {item_type} for the entry "
                f"{entry_name.name} of the attribute {att_name} "
                f"not declared in ontology.")

        # Make sure the import of these related types are handled.
        manager.add_object_to_import(item_type)

        self_ref = entry_name.class_name == item_type

        return ListProperty(
            manager, att_name, item_type, description=desc,
            default_val=[], self_ref=self_ref)
    def parse_dict(
        self,
        manager: ImportManager,
        schema: Dict,
        entry_name: EntryName,
        att_name: str,
        att_type: str,
        desc: str,
    ):
        if (SchemaKeywords.dict_key_type not in schema
                or SchemaKeywords.dict_value_type not in schema):
            raise TypeNotDeclaredException(
                f"Item type of the attribute {att_name} for the entry "
                f" {entry_name.class_name} not declared. This attribute is "
                f"a composite type: {att_type}, it should have a "
                f"{SchemaKeywords.dict_key_type} and "
                f"{SchemaKeywords.dict_value_type}.")

        key_type = schema[SchemaKeywords.dict_key_type]
        if not valid_composite_key(key_type):
            raise UnsupportedTypeException(
                f"Key type {key_type} for entry {entry_name.name}'s "
                f"attribute {att_name} is not supported, we only support a "
                f"limited set of keys.")

        value_type = schema[SchemaKeywords.dict_value_type]
        if is_composite_type(value_type):
            # Case of nested.
            raise UnsupportedTypeException(
                f"Item type {value_type} for entry {entry_name.name}'s "
                f"attribute {att_name} is a composite type, we do not support "
                f"nested composite type.")

        if not manager.is_known_name(value_type):
            # Case of unknown.
            raise TypeNotDeclaredException(
                f"Item type {value_type} for the entry "
                f"{entry_name.name} of the attribute {att_name} "
                f"not declared in ontology.")

        # Make sure the import of these related types are handled.
        manager.add_object_to_import(value_type)

        self_ref = entry_name.class_name == value_type

        default_val: Dict = {}

        return DictProperty(
            manager,
            att_name,
            key_type,
            value_type,
            description=desc,
            default_val=default_val,
            self_ref=self_ref,
        )
    def parse_property(self, entry_name: EntryName, schema: Dict) -> Property:
        """
        Parses instance and class properties defined in an entry schema and
        checks for the constraints allowed by the ontology generation system.

        Args:
            entry_name: Entry Name object that contains various form of the
              entry's name.
            schema: Entry definition schema
        Returns: An object of class `code_generation_util.FileItem` containing
         the generated code.
        """
        att_name = schema[SchemaKeywords.attribute_name]
        att_type = schema[SchemaKeywords.attribute_type]

        manager: ImportManager = self.import_managers.get(
            entry_name.module_name)

        # schema type should be present in the validation tree
        # TODO: Remove this hack
        if not manager.is_known_name(att_type):
            raise TypeNotDeclaredException(
                f"Attribute type '{att_type}' for the entry "
                f"'{entry_name.name}' of the attribute '{att_name}' not "
                f"declared in the ontology")

        desc = schema.get(SchemaKeywords.description, None)
        default_val = schema.get(SchemaKeywords.default_value, None)

        # element type should be present in the validation tree
        if att_type in COMPOSITES:
            if att_type == "List":
                return self.parse_list(manager, schema, entry_name, att_name,
                                       att_type, desc)
            elif att_type == "Dict":
                return self.parse_dict(manager, schema, entry_name, att_name,
                                       att_type, desc)
        elif att_type in NON_COMPOSITES or manager.is_imported(att_type):
            self_ref = entry_name.class_name == att_type
            return self.parse_non_composite(
                manager,
                att_name,
                att_type,
                desc,
                default_val,
                self_ref=self_ref,
            )

        raise UnsupportedTypeException(f"{att_type} is not a supported type.")
Пример #4
0
    def parse_entry(self, entry_name: EntryName,
                    schema: Dict) -> Tuple[EntryDefinition, List[str]]:
        """
        Args:
            entry_name: Object holds various name form of the entry.
            schema: Dictionary containing specifications for an entry.

        Returns: extracted entry information: entry package string, entry
        filename, entry class entry_name, generated entry code and entry
        attribute names.
        """
        this_manager = self.import_managers.get(entry_name.module_name)

        # Determine the parent entry of this entry.
        parent_entry: str = schema[SchemaKeywords.parent_entry]

        if parent_entry.startswith(TOP_MOST_MODULE_NAME):
            raise ParentEntryNotSupportedException(
                f"The parent entry {parent_entry} cannot be directly inherited,"
                f" please inherit a type from {top.__name__} or your own"
                f" ontology.")

        if not this_manager.is_imported(parent_entry):
            raise ParentEntryNotDeclaredException(
                f"The parent entry {parent_entry} is not declared. It is "
                f"neither in the base entries nor in custom entries. "
                f"Please check them ontology specification, and make sure the "
                f"entry is defined before this.")

        base_entry: Optional[str] = self.find_base_entry(
            entry_name.class_name, parent_entry)

        if base_entry is None:
            raise OntologySpecError(
                f"Cannot find the base entry for entry "
                f"{entry_name.class_name} and {parent_entry}")

        if base_entry not in self.top_init_args:
            raise ParentEntryNotSupportedException(
                f"Cannot add {entry_name.class_name} to the ontology as "
                f"it's parent entry {parent_entry} is not supported. This is "
                f"likely that the entries are not inheriting the allowed types."
            )

        # Take the property definitions of this entry.
        properties: List[Dict] = schema.get(SchemaKeywords.attributes, [])

        this_manager = self.import_managers.get(entry_name.module_name)

        # Validate if the parent entry is present.
        if not this_manager.is_known_name(parent_entry):
            raise ParentEntryNotDeclaredException(
                f"Cannot add {entry_name.class_name} to the ontology as "
                f"it's parent entry {parent_entry} is not present "
                f"in the ontology.")

        parent_entry_use_name = this_manager.get_name_to_use(parent_entry)

        property_items, property_names = [], []
        for prop_schema in properties:
            # TODO: add test
            prop_name = prop_schema["name"]
            if prop_name in RESERVED_ATTRIBUTE_NAMES:
                raise InvalidIdentifierException(
                    f"The attribute name {prop_name} is reserved and cannot be "
                    f"used, please consider changed the name. The list of "
                    f"reserved name strings are "
                    f"{RESERVED_ATTRIBUTE_NAMES}")

            property_names.append(prop_schema["name"])
            property_items.append(self.parse_property(entry_name, prop_schema))

        # For special classes that requires a constraint.
        core_bases: Set[str] = self.top_to_core_entries[base_entry]
        entry_constraint_keys: Dict[str, str] = {}
        if any(item == "BaseLink" for item in core_bases):
            entry_constraint_keys = DEFAULT_CONSTRAINTS_KEYS["BaseLink"]
        elif any(item == "BaseGroup" for item in core_bases):
            entry_constraint_keys = DEFAULT_CONSTRAINTS_KEYS["BaseGroup"]

        class_att_items: List[ClassTypeDefinition] = []
        for schema_key, class_key in entry_constraint_keys.items():
            if schema_key in schema:
                constraint_type_ = schema[schema_key]
                constraint_type_name = this_manager.get_name_to_use(
                    constraint_type_)

                if constraint_type_name is None:
                    raise TypeNotDeclaredException(
                        f"The type {constraint_type_} is not defined but it is "
                        f"specified in {schema_key} of the definition of "
                        f"{schema['entry_name']}. Please define them before "
                        f"this entry type.")

                # TODO: cannot handle constraints that contain self-references.
                # self_ref = entry_name.class_name == constraint_type_

                class_att_items.append(
                    ClassTypeDefinition(class_key, constraint_type_name))

        # TODO: Can assign better object type to Link and Group objects
        custom_init_arg_str: str = self.construct_init(entry_name, base_entry)

        entry_item = EntryDefinition(
            name=entry_name.name,
            class_type=parent_entry_use_name,
            init_args=custom_init_arg_str,
            properties=property_items,
            class_attributes=class_att_items,
            description=schema.get(SchemaKeywords.description, None),
        )

        return entry_item, property_names