def parse_ontology_content_property(self, ontology_content, new_property_proxy_order, model_proxy):

        new_property_proxy_name = ontology_content["name"]
        new_property_proxy_id = ontology_content.get("id")
        new_property_proxy_field_type = QPropertyTypes.get(ontology_content["property_type"])
        assert new_property_proxy_field_type is not None, "invalid property_type specified"

        (new_property_proxy, created_property_proxy) = QPropertyProxy.objects.get_or_create(
            # these fields are the "defining" ones (other fields can change below w/out creating new proxies)
            ontology=self,
            model_proxy=model_proxy,
            name=new_property_proxy_name,
            cim_id=new_property_proxy_id,
            field_type=new_property_proxy_field_type,
        )

        category_id = ontology_content.get("category_id")
        new_property_proxy.category_id = category_id
        new_property_proxy.category_proxy = find_in_sequence(lambda c: c.cim_id == category_id, model_proxy.category_proxies.all())

        new_property_proxy.order = new_property_proxy_order
        new_property_proxy.is_meta = ontology_content.get("is_meta", False)
        new_property_proxy.is_nillable = ontology_content.get("is_nillable", False)
        new_property_proxy.is_hierarchical = ontology_content.get("is_hierarchical", False)
        new_property_proxy_documentation = ontology_content.get("documentation")
        if new_property_proxy_documentation:
            new_property_proxy.documentation = remove_spaces_and_linebreaks(new_property_proxy_documentation)
        new_property_proxy_cardinality = re.split("\.|,", ontology_content.get("cardinality"))  # TODO: DECIDE ONCE-AND-FOR-ALL IF "cardinality" IS SPLIT ON '.' OR ','
        new_property_proxy.cardinality_min = new_property_proxy_cardinality[0]
        new_property_proxy.cardinality_max = new_property_proxy_cardinality[1]
        new_property_proxy.values = ontology_content.get("values")
        if new_property_proxy_field_type == QPropertyTypes.ATOMIC:
            new_property_proxy_atomic_type_type = ontology_content.get("atomic_type")
            if new_property_proxy_atomic_type_type == "STRING":
                new_property_proxy_atomic_type_type = "DEFAULT"
            new_property_proxy_atomic_type = QAtomicTypes.get(new_property_proxy_atomic_type_type)
            assert new_property_proxy_atomic_type is not None, "invalid atomic_type specified"
            new_property_proxy.atomic_type = new_property_proxy_atomic_type
        elif new_property_proxy_field_type == QPropertyTypes.ENUMERATION:
            new_property_proxy.enumeration_is_open = ontology_content.get("enumeration_is_open")
            new_property_proxy.enumeration_choices = ontology_content.get("enumeration_members")
        else:  # new_property_proxy_field_type == QPropertyTypes.RELATIONSHIP
            new_property_proxy.relationship_target_names = ontology_content.get("relationship_targets")  # target_names are set now; target_models are set later in  "QPropertyProxy.reset"

        new_property_proxy.save()

        return new_property_proxy
    def parse_ontology_content_category(self, ontology_content, new_category_proxy_order, model_proxy):
        new_category_proxy_name = ontology_content["name"]
        new_category_proxy_id = ontology_content["id"]

        (new_category_proxy, created_category_proxy) = QCategoryProxy.objects.get_or_create(
            # these fields are the "defining" ones (other fields can change below w/out creating new proxies)
            ontology=self,
            model_proxy=model_proxy,
            name=new_category_proxy_name,
            cim_id=new_category_proxy_id,
        )

        new_category_proxy.order = new_category_proxy_order
        new_category_proxy_documentation = ontology_content.get("documentation")
        if new_category_proxy_documentation:
            new_category_proxy.documentation = remove_spaces_and_linebreaks(new_category_proxy_documentation)

        new_category_proxy.save()

        return new_category_proxy
예제 #3
0
    def register_cim1(self, **kwargs):

        request = kwargs.pop("request", None)

        try:
            self.file.open()
            ontology_content = et.parse(self.file)
            self.file.close()
        except IOError:
            msg = "Error opening file: %s" % self.file
            if request:
                messages.add_message(request, messages.ERROR, msg)
                return

        recategorization_needed = False

        old_model_proxies = list(self.model_proxies.all())  # list forces qs evaluation immediately
        new_model_proxies = []

        for i, model_proxy in enumerate(xpath_fix(ontology_content, "//classes/class")):

            model_proxy_ontology = self
            model_proxy_name = xpath_fix(model_proxy, "name/text()")[0]
            model_proxy_stereotype = get_index(xpath_fix(model_proxy, "@stereotype"), 0)
            model_proxy_namespace = get_index(xpath_fix(model_proxy, "@namespace"), 0)
            model_proxy_package = get_index(xpath_fix(model_proxy, "@package"), 0)
            model_proxy_documentation = get_index(xpath_fix(model_proxy, "description/text()"), 0)
            if model_proxy_documentation:
                model_proxy_documentation = remove_spaces_and_linebreaks(model_proxy_documentation)
            else:
                model_proxy_documentation = u""

            (new_model_proxy, created_model_proxy) = QModelProxy.objects.get_or_create(
                ontology=model_proxy_ontology,
                name=model_proxy_name,
            )

            if created_model_proxy:
                recategorization_needed = True

            new_model_proxy.order = i + 1
            new_model_proxy.stereotype = model_proxy_stereotype
            new_model_proxy.namespace = model_proxy_namespace
            new_model_proxy.package = model_proxy_package
            new_model_proxy.documentation = model_proxy_documentation
            new_model_proxy.save()
            new_model_proxies.append(new_model_proxy)

            old_property_proxies = list(new_model_proxy.standard_properties.all())  # list forces qs evaluation immediately
            new_property_proxies = []

            for j, property_proxy in enumerate(xpath_fix(model_proxy, "attributes/attribute")):

                property_proxy_name = re.sub(r'\.', '_', str(xpath_fix(property_proxy, "name/text()")[0]))
                property_proxy_field_type = xpath_fix(property_proxy, "type/text()")[0]
                property_proxy_is_label = get_index(xpath_fix(property_proxy, "@is_label"), 0)
                property_proxy_stereotype = get_index(xpath_fix(property_proxy, "@stereotype"), 0)
                property_proxy_namespace = get_index(xpath_fix(property_proxy, "@namespace"), 0)
                property_proxy_required = get_index(xpath_fix(property_proxy, "@required"), 0)
                property_proxy_documentation = get_index(xpath_fix(property_proxy, "description/text()"), 0)
                if property_proxy_documentation:
                    property_proxy_documentation = remove_spaces_and_linebreaks(property_proxy_documentation)
                else:
                    property_proxy_documentation = u""
                property_proxy_atomic_type = get_index(xpath_fix(property_proxy, "atomic/atomic_type/text()"), 0)
                if property_proxy_atomic_type:
                    if property_proxy_atomic_type == u"STRING":
                        property_proxy_atomic_type = u"DEFAULT"
                    property_proxy_atomic_type = QAtomicPropertyTypes.get(property_proxy_atomic_type)
                property_proxy_enumeration_choices = []
                for property_proxy_enumeration_choice in xpath_fix(property_proxy, "enumeration/choice"):
                    property_proxy_enumeration_choices.append(xpath_fix(property_proxy_enumeration_choice, "text()")[0])
                property_proxy_relationship_cardinality_min = get_index(xpath_fix(property_proxy, "relationship/cardinality/@min"), 0)
                property_proxy_relationship_cardinality_max = get_index(xpath_fix(property_proxy, "relationship/cardinality/@max"), 0)
                property_proxy_relationship_target_name = get_index(xpath_fix(property_proxy, "relationship/target/text()"), 0)

                (new_property_proxy, created_property) = QStandardPropertyProxy.objects.get_or_create(
                    model_proxy=new_model_proxy,
                    name=property_proxy_name,
                    field_type=property_proxy_field_type
                )

                if created_property:
                    recategorization_needed = True

                new_property_proxy.order = j + 1
                new_property_proxy.documentation = property_proxy_documentation
                new_property_proxy.is_label = property_proxy_is_label == "true"
                new_property_proxy.stereotype = property_proxy_stereotype
                new_property_proxy.namespace = property_proxy_namespace
                if property_proxy_field_type == QPropertyTypes.RELATIONSHIP:
                    if property_proxy_relationship_cardinality_min and property_proxy_relationship_cardinality_max:
                        new_property_proxy.cardinality = u"%s|%s" % (property_proxy_relationship_cardinality_min, property_proxy_relationship_cardinality_max)
                else:
                    if property_proxy_required:
                        new_property_proxy.cardinality = u"1|1"
                new_property_proxy.atomic_type = property_proxy_atomic_type
                new_property_proxy.enumeration_choices = "|".join(property_proxy_enumeration_choices)
                new_property_proxy.relationship_target_name = property_proxy_relationship_target_name
                new_property_proxy.save()
                new_property_proxies.append(new_property_proxy)

            # if there's anything in old_property_proxies not in new_property_proxies, delete it
            for old_property_proxy in old_property_proxies:
                if old_property_proxy not in new_property_proxies:
                    old_property_proxy.delete()

            new_model_proxy.save()  # save parent again for the m2m relationship

        # if there's anything in old_model_proxies not in new_model_proxies, delete it
        for old_model_proxy in old_model_proxies:
            if old_model_proxy not in new_model_proxies:
                old_model_proxy.delete()

        # reset whatever's left
        for model_proxy in QModelProxy.objects.filter(ontology=self):
            for property_proxy in model_proxy.standard_properties.all():
                property_proxy.reset()
                property_proxy.save()

        if recategorization_needed:
            msg = "Since you are re-registering an existing version, you will also have to re-register the corresponding categorization"
            if request:
                messages.add_message(request, messages.WARNING, msg)
    def parse_ontology_content_model(self, ontology_content, new_model_proxy_order):

        new_model_proxy_name = ontology_content["name"]
        new_model_proxy_package = ontology_content["package"]
        # a SPECIALIZATION model ought to have an explicit id; a SCHEMA model can just create one dynamically
        new_model_proxy_id = ontology_content.get("id", "{}.{}".format(self.key, new_model_proxy_name))

        parent_model_proxy = None
        if self.parent:
            try:
                parent_model_proxy = self.parent.model_proxies.get(package=new_model_proxy_package, name=new_model_proxy_name)
            except QModelProxy.DoesNotExist:
                # not everything in a specialization has to be based on a parent model, right?
                pass

        (new_model_proxy, created_model_proxy) = QModelProxy.objects.get_or_create(
            # these fields are the "defining" ones (other fields can change below w/out creating new proxies)
            ontology=self,
            name=new_model_proxy_name,
            package=new_model_proxy_package,
            cim_id=new_model_proxy_id,
        )

        new_model_proxy.order = new_model_proxy_order
        new_model_proxy.is_document = ontology_content.get("is_document", False)
        new_model_proxy.is_meta = ontology_content.get("is_meta", False)
        new_model_proxy_documentation = ontology_content.get("documentation")
        if new_model_proxy_documentation:
            new_model_proxy.documentation = remove_spaces_and_linebreaks(new_model_proxy_documentation)
        new_model_proxy_label = ontology_content.get("label")
        if new_model_proxy_label is None and parent_model_proxy is not None:
            new_model_proxy_label = parent_model_proxy.label
        new_model_proxy.label = new_model_proxy_label

        new_model_proxy.save()

        # ...now add any categories...

        old_category_proxies = list(new_model_proxy.category_proxies.all())
        new_category_proxies = []

        inherited_categories = ontology_content["categories"]["inherited"]  # inherited categories are included at the start
        excluded_categories = ontology_content["categories"]["excluded"]  # excluded categories don't have to be uesd at all
        defined_categories = ontology_content["categories"]["defined"]  # defined categories are added as normal

        if parent_model_proxy:
            for inherited_category_order, inherited_category_proxy in enumerate(parent_model_proxy.category_proxies.filter(name__in=inherited_categories), start=1):
                new_model_proxy.category_proxies.add(inherited_category_proxy)
                new_category_proxies.append(inherited_category_proxy)
        else:
            assert len(inherited_categories) == 0, "it makes no sense to specify 'inherited_categories' w/out providing a base model"

        for ontology_category_order, ontology_category in enumerate(defined_categories, start=len(new_category_proxies) + 1):
            new_category_proxy = self.parse_ontology_content_category(ontology_category, ontology_category_order, new_model_proxy)
            new_category_proxies.append(new_category_proxy)

        # TODO: ONLY DELETE A category_proxy IF THERE ARE NO OTHER MODELS (FROM ANY ONTOLOGY) LINKED TO IT
        for old_category_proxy in old_category_proxies:
            if old_category_proxy not in new_category_proxies:
                old_category_proxy.delete()

        # (don't forget to create a placeholder category for properties that are uncategorized)
        uncategorized_category_proxy, created_uncategorized_category_proxy = QCategoryProxy.objects.get_or_create(
            ontology=self,
            model_proxy=new_model_proxy,
            name=UNCATEGORIZED_CATEGORY_PROXY_NAME,
            is_uncategorized=True,
        )
        if created_uncategorized_category_proxy:
            uncategorized_category_proxy.order = len(new_category_proxies) + 1
            uncategorized_category_proxy.save()
            new_category_proxies.append(uncategorized_category_proxy)

        # ...now add any properties...

        old_property_proxies = list(new_model_proxy.property_proxies.all())
        new_property_proxies = []

        inherited_properties = ontology_content["properties"]["inherited"]  # inherited properties are included at the start
        excluded_properties = ontology_content["properties"]["excluded"]  # excluded properties don't have to be uesd at all
        defined_properties = ontology_content["properties"]["defined"]  # defined properties are added as normal

        if parent_model_proxy:
            for inherited_property_order, inherited_property_proxy in enumerate(parent_model_proxy.property_proxies.filter(name__in=inherited_properties), start=1):
                new_model_proxy.property_proxies.add(inherited_property_proxy)
                new_property_proxies.append(inherited_property_proxy)
        else:
            assert len(inherited_properties) == 0, "it makes no sense to specify 'inherited_properties' w/out providing a base model"

        for ontology_property_order, ontology_property in enumerate(defined_properties, start=len(new_property_proxies) + 1):
            new_property_proxy = self.parse_ontology_content_property(ontology_property, ontology_property_order, new_model_proxy)
            new_property_proxies.append(new_property_proxy)

        # TODO: ONLY DELETE A property_proxy IF THERE ARE NO OTHER MODELS (FROM ANY ONTOLOGY) LINKED TO IT
        for old_property_proxy in old_property_proxies:
            if old_property_proxy not in new_property_proxies:
                old_property_proxy.delete()

        return new_model_proxy
    def parse_ontology_content(self, ontology_content):

        # 1st do some logical checks on the content...

        # name should match
        ontology_name = ontology_content.get("name")
        if self.name != ontology_name:
            msg = "The name of this ontology instance does not match that found in the QConfig file"
            raise QError(msg)

        # version should match(ish)
        ontology_version = ontology_content.get("version")
        if self.version.major() != Version(ontology_version).major():
            msg = "The major version of this ontology instance does not match that found in the QConfig file"
            raise QError(msg)

        # documentation can be overwritten
        ontology_documentation = ontology_content.get("documentation")
        if ontology_documentation:
            self.documentation = remove_spaces_and_linebreaks(ontology_documentation)

        # type should match...
        ontology_type = QOntologyTypes.get(ontology_content.get("ontology_type"))
        assert ontology_type is not None, "invalid ontology_type specified"
        if self.ontology_type != ontology_type:
            msg = "The ontology_type of this ontology instance does not match that found in the QConfig file"
            raise QError(msg)

        # if specified, parent must match (and it must be specified for SPECIALIZATIONS)
        ontology_base_key = ontology_content.get("ontology_base")
        if ontology_base_key:
            ontology_base = QOntology.objects.has_key(ontology_base_key).first()
            # (self.parent.is_registered will already have been checked by the "register" fn)
            if self.parent != ontology_base:
                msg = "The ontology_base of this ontology instance does not match that found in the QConfig file"
                raise QError(msg)
        elif ontology_type == QOntologyTypes.SPECIALIZATION:
            msg = "A SPECIALIZATION must include an ontology_base"
            raise QError(msg)

        # now create / setup all of the proxies contained in this ontology...

        old_model_proxies = list(self.model_proxies.all())
        new_model_proxies = []

        inherited_classes = ontology_content["classes"]["inherited"]  # inherited classes are included at the start
        excluded_classes = ontology_content["classes"]["excluded"]  # excluded classes don't have to be used at all
        defined_classes = ontology_content["classes"]["defined"]  # defined classes are added as normal

        # AS OF V0.17.0, PROXIES ARE NOT CONSTRAINED BY ONTOLOGY;
        # THEREFORE THERE IS NO NEED TO COPY INHERITED PROXIES ACROSS
        # (THAT'S WHY I DON'T NEED "inherited_model_proxies" BELOW)
        # if self.parent:
        #     inherited_model_proxies = self.parent.model_proxies.in_fully_qualified_names(inherited_classes)
        assert len(inherited_classes) == 0

        for ontology_model_order, ontology_model in enumerate(defined_classes, start=len(new_model_proxies)+1):
            new_model_proxy = self.parse_ontology_content_model(ontology_model, ontology_model_order)
            new_model_proxies.append(new_model_proxy)

        # if there's anything in old_model_proxies not in new_model_proxies, delete it...
        for old_model_proxy in old_model_proxies:
            if old_model_proxy not in new_model_proxies:
                old_model_proxy.delete()

        # reset whatever's left...
        for model_proxy in QModelProxy.objects.filter(ontology=self):
            model_proxy.reset(force_save=True)
            for category_proxy in model_proxy.category_proxies.filter(ontology=self):
                category_proxy.reset(force_save=True)
            for property_proxy in model_proxy.property_proxies.filter(ontology=self):
                property_proxy.reset(force_save=True)
    def create_component_proxy(self, component_proxy_node, parent_component_proxy=None):
        """
        recursively create component proxies, keeping track of their hierarchy
        :param component_proxy_node:
        :param parent_component_proxy:
        :return:
        """

        self.component_order += 1

        component_proxy_vocabulary = self
        component_proxy_name = get_index(xpath_fix(component_proxy_node, "@name"), 0)
        component_proxy_order = self.component_order
        component_proxy_documentation = get_index(xpath_fix(component_proxy_node, "definition/text()"), 0)
        if component_proxy_documentation:
            component_proxy_documentation = remove_spaces_and_linebreaks(component_proxy_documentation)

        (new_component_proxy, created_component_proxy) = QComponentProxy.objects.get_or_create(
            vocabulary=component_proxy_vocabulary,
            name=component_proxy_name,
            parent=parent_component_proxy
        )

        new_component_proxy.documentation = component_proxy_documentation
        new_component_proxy.order = component_proxy_order
        new_component_proxy.save()

        old_category_proxies = list(new_component_proxy.category_proxies.all())  # list forces qs evaluation immediately
        new_category_proxies = []

        category_proxy_component = new_component_proxy
        for i, category_proxy_node in enumerate(xpath_fix(component_proxy_node, "./parametergroup")):

            category_proxy_name = xpath_fix(category_proxy_node, "@name")[0]
            category_proxy_key = slugify(category_proxy_name)
            category_proxy_order = i + 1
            category_proxy_documentation = get_index(xpath_fix(category_proxy_node, "definition/text()"), 0)
            if category_proxy_documentation:
                category_proxy_documentation = remove_spaces_and_linebreaks(category_proxy_documentation)

            (new_category_proxy, created_category_proxy) = QScientificCategoryProxy.objects.get_or_create(
                component_proxy=category_proxy_component,
                name=category_proxy_name
            )

            new_category_proxy.documentation = category_proxy_documentation
            new_category_proxy.order = category_proxy_order
            new_category_proxy.key = category_proxy_key
            new_category_proxy.save()

            new_category_proxies.append(new_category_proxy)

            old_property_proxies = list(new_category_proxy.properties.all())  # list forces qs evaluation immediately
            new_property_proxies = []

            property_proxy_component = new_component_proxy
            property_proxy_category = new_category_proxy
            for j, property_proxy_node in enumerate(xpath_fix(category_proxy_node, "./parameter")):

                property_proxy_name = get_index(xpath_fix(property_proxy_node, "@name"), 0)
                property_proxy_choice = get_index(xpath_fix(property_proxy_node, "@choice"), 0)
                property_proxy_order = j + 1
                property_proxy_documentation = get_index(xpath_fix(property_proxy_node, "definition/text()"), 0)
                if property_proxy_documentation:
                    property_proxy_documentation = remove_spaces_and_linebreaks(property_proxy_documentation)
                property_proxy_enumeration_values = []
                for property_proxy_enumeration_value in xpath_fix(property_proxy_node, "value"):
                    property_proxy_enumeration_value_name = get_index(xpath_fix(property_proxy_enumeration_value, "@name"), 0)
                    if property_proxy_enumeration_value_name:
                        property_proxy_enumeration_values.append(property_proxy_enumeration_value_name)

                (new_property_proxy, created_property_proxy) = QScientificPropertyProxy.objects.get_or_create(
                    component_proxy=property_proxy_component,
                    category=property_proxy_category,
                    name=property_proxy_name,
                )

                new_property_proxy.choice = property_proxy_choice
                new_property_proxy.documentation = property_proxy_documentation
                new_property_proxy.order = property_proxy_order
                new_property_proxy.enumeration_choices = "|".join(property_proxy_enumeration_values)
                new_property_proxy.save()

                new_property_proxies.append(new_property_proxy)

            # if there's anything in old_property_proxies not in new_property_proxies, delete it
            for old_property_proxy in old_property_proxies:
                if old_property_proxy not in new_property_proxies:
                    old_property_proxy.delete()

            # reset whatever's left
            for property_proxy in QScientificPropertyProxy.objects.filter(component_proxy=new_component_proxy, category=new_category_proxy):
                property_proxy.reset()
                property_proxy.save()

        # if there's anything in old_category_proxies not in new_category_proxies, delete it
        for old_category_proxy in old_category_proxies:
            if old_category_proxy not in new_category_proxies:
                old_category_proxy.delete()

        # recurse
        for child_component_proxy_node in xpath_fix(component_proxy_node, "./component"):
            self.create_component_proxy(child_component_proxy_node, new_component_proxy)

        # (do this last in case any m2m fields are added recursively)
        self.new_component_proxies.append(new_component_proxy)
    def register(self, **kwargs):

        request = kwargs.pop("request", None)

        try:
            self.file.open()
            categorization_content = et.parse(self.file)
            self.file.close()
        except IOError:
            msg = "Error opening file: %s" % self.file
            if request:
                messages.add_message(request, messages.ERROR, msg)
                return

        ontologies = self.ontologies.all()
        if not ontologies:
            msg = "QCategorization '%s' has not been associated with any ontologies.  It's kind of silly to register it now." % (self)
            if request:
                messages.add_message(request, messages.WARNING, msg)
            else:
                print(msg)

        old_category_proxies = list(self.category_proxies.all())  # list forces qs evaluation immediately
        new_category_proxies = []

        for i, category_proxy in enumerate(xpath_fix(categorization_content, "//category")):

            category_proxy_categorization = self
            category_proxy_name = get_index(xpath_fix(category_proxy, "name/text()"), 0)
            category_proxy_key = get_index(xpath_fix(category_proxy, "key/text()"), 0)
            category_proxy_order = get_index(xpath_fix(category_proxy, 'order/text()'), 0)
            category_proxy_documentation = get_index(xpath_fix(category_proxy, "description/text()"), 0)
            if category_proxy_documentation:
                category_proxy_documentation = remove_spaces_and_linebreaks(category_proxy_documentation)

            (new_category_proxy, created_category) = QStandardCategoryProxy.objects.get_or_create(
                categorization=category_proxy_categorization,
                name=category_proxy_name,
            )

            new_category_proxy.documentation = category_proxy_documentation
            new_category_proxy.key = category_proxy_key or slugify(category_proxy_name)
            new_category_proxy.order = category_proxy_order or i

            if not created_category:
                # remove any existing relationships (going to replace them during this registration)...
                new_category_proxy.properties.clear()

            for j, field in enumerate(xpath_fix(categorization_content, "//field[category_key='%s']" % new_category_proxy.key)):

                model_name = get_index(xpath_fix(field, "./ancestor::model/name/text()"), 0)
                field_name = get_index(xpath_fix(field, "name/text()"), 0)

                for ontology in ontologies:
                    try:
                        model_proxy = ontology.model_proxies.get(name__iexact=model_name)
                        property_proxy = model_proxy.standard_properties.get(name__iexact=field_name)
                        new_category_proxy.properties.add(property_proxy)

                    except QModelProxy.DoesNotExist:
                        msg = "Unable to find QModel '%s' specified in QCategorization '%s'" % (model_name, self)
                        if request:
                            messages.add_message(request, messages.WARNING, msg)
                        else:
                            print(msg)
                            pass
                    except QStandardPropertyProxy.DoesNotExist:
                        msg = "Unable to find QStandardProperty '%s' specified in QCategorization '%s'" % (field_name, self)
                        if request:
                            messages.add_message(request, messages.WARNING, msg)
                        else:
                            print(msg)
                            pass

            new_category_proxy.save()
            new_category_proxies.append(new_category_proxy)

        self.is_registered = True
        self.last_registered_version = self.version
    def parse_schema(self, **kwargs):
        """
        registers a CIM2 ontology schema QXML file
        :param kwargs:
        :return:
        """

        request = kwargs.pop("request", None)

        try:
            self.file.open()
            ontology_content = et.parse(self.file)
            self.file.close()
        except IOError as e:
            msg = "Error opening file: {0}".format(self.file)
            if request:
                messages.add_message(request, messages.ERROR, msg)
            raise e

        recategorization_needed = False

        # name can be anything...
        ontology_name = get_index(xpath_fix(ontology_content, "name/text()"), 0)

        # version should match(ish) the instance field...
        ontology_version = get_index(xpath_fix(ontology_content, "version/text()"), 0)
        if self.version.major() != Version(ontology_version).major():
            msg = "The major version of this ontology instance does not match the major version of the QXML file"
            if request:
                messages.add_message(request, messages.WARNING, msg)

        # description can overwrite the instance field...
        ontology_description = get_index(xpath_fix(ontology_content, "description/text()"), 0)
        if ontology_description:
            self.description = remove_spaces_and_linebreaks(ontology_description)

        old_model_proxies = list(self.model_proxies.all())  # list forces qs evaluation immediately
        new_model_proxies = []

        for i, model_proxy in enumerate(xpath_fix(ontology_content, "//classes/class"), start=1):
            model_proxy_package = xpath_fix(model_proxy, "@package")[0]
            model_proxy_schema = self
            model_proxy_name = xpath_fix(model_proxy, "name/text()")[0]
            model_proxy_stereotype = get_index(xpath_fix(model_proxy, "@stereotype"), 0)
            model_proxy_documentation = get_index(xpath_fix(model_proxy, "description/text()"), 0)
            if model_proxy_documentation:
                model_proxy_documentation = remove_spaces_and_linebreaks(model_proxy_documentation)
            else:
                model_proxy_documentation = u""

            (new_model_proxy, created_model_proxy) = QModelProxy.objects.get_or_create(
                package=model_proxy_package, ontology=model_proxy_schema, name=model_proxy_name
            )

            if created_model_proxy:
                recategorization_needed = True

            new_model_proxy.order = i
            new_model_proxy.stereotype = model_proxy_stereotype
            new_model_proxy.documentation = model_proxy_documentation
            new_model_proxy.save()
            new_model_proxies.append(new_model_proxy)

            old_property_proxies = list(new_model_proxy.property_proxies.all())  # list forces qs evaluation immediately
            new_property_proxies = []

            for j, property_proxy in enumerate(xpath_fix(model_proxy, "attributes/attribute"), start=1):
                property_proxy_name = re.sub(r"\.", "_", str(xpath_fix(property_proxy, "name/text()")[0]))
                property_proxy_field_type = xpath_fix(property_proxy, "type/text()")[0]
                property_proxy_stereotype = get_index(xpath_fix(property_proxy, "@stereotype"), 0)
                property_proxy_documentation = get_index(xpath_fix(property_proxy, "description/text()"), 0)
                if property_proxy_documentation:
                    property_proxy_documentation = remove_spaces_and_linebreaks(property_proxy_documentation)
                else:
                    property_proxy_documentation = u""
                property_proxy_cardinality_min = get_index(xpath_fix(property_proxy, "cardinality/@min"), 0)
                property_proxy_cardinality_max = get_index(xpath_fix(property_proxy, "cardinality/@max"), 0)
                property_proxy_is_nillable = get_index(xpath_fix(property_proxy, "@is_nillable"), 0)

                (new_property_proxy, created_property) = QPropertyProxy.objects.get_or_create(
                    model_proxy=new_model_proxy, name=property_proxy_name, field_type=property_proxy_field_type
                )

                if created_property:
                    recategorization_needed = True

                new_property_proxy.order = j
                new_property_proxy.documentation = property_proxy_documentation
                new_property_proxy.stereotype = property_proxy_stereotype
                new_property_proxy.cardinality = "{0}|{1}".format(
                    property_proxy_cardinality_min,
                    property_proxy_cardinality_max if property_proxy_cardinality_max != "N" else "*",
                )
                new_property_proxy.is_nillable = property_proxy_is_nillable

                # atomic properties...
                property_proxy_atomic_type = get_index(xpath_fix(property_proxy, "atomic/atomic_type/text()"), 0)
                if property_proxy_atomic_type:
                    if property_proxy_atomic_type == u"STRING":
                        property_proxy_atomic_type = u"DEFAULT"
                    property_proxy_atomic_type = QAtomicPropertyTypes.get(property_proxy_atomic_type)
                    new_property_proxy.atomic_type = property_proxy_atomic_type

                # relationship properties...
                property_proxy_relationship_target_names = "|".join(
                    # note that each target_name is fully-qualified
                    xpath_fix(property_proxy, "relationship/targets/target/text()")
                )
                new_property_proxy.relationship_target_names = property_proxy_relationship_target_names

                # enumeration properties...
                property_proxy_enumeration_is_open = get_index(xpath_fix(property_proxy, "enumeration/@is_open"), 0)
                property_proxy_enumeration_is_multi = get_index(xpath_fix(property_proxy, "enumeration/@is_multi"), 0)
                if property_proxy_enumeration_is_open:
                    new_property_proxy.enumeration_is_open = property_proxy_enumeration_is_open == "true"
                if property_proxy_enumeration_is_multi:
                    new_property_proxy.enumeration_is_multi = property_proxy_enumeration_is_multi == "true"
                property_proxy_enumeration = []
                for k, enumeration_member_proxy in enumerate(
                    xpath_fix(property_proxy, "enumeration/choices/choice"), start=1
                ):
                    enumeration_member_proxy_value = get_index(xpath_fix(enumeration_member_proxy, "value/text()"), 0)
                    enumeration_member_proxy_documentation = get_index(
                        xpath_fix(enumeration_member_proxy, "description/text()"), 0
                    )
                    property_proxy_enumeration_member = {
                        "order": k,
                        "value": enumeration_member_proxy_value,
                        "name": enumeration_member_proxy_value,
                        "documentation": enumeration_member_proxy_documentation,
                    }
                    property_proxy_enumeration.append(property_proxy_enumeration_member)
                new_property_proxy.enumeration = property_proxy_enumeration

                new_property_proxy.save()
                new_property_proxies.append(new_property_proxy)

            # if there's anything in old_property_proxies not in new_property_proxies, delete it
            for old_property_proxy in old_property_proxies:
                if old_property_proxy not in new_property_proxies:
                    old_property_proxy.delete()

            new_model_proxy.save()  # save parent again for the m2m relationship

        # if there's anything in old_model_proxies not in new_model_proxies, delete it
        for old_model_proxy in old_model_proxies:
            if old_model_proxy not in new_model_proxies:
                old_model_proxy.delete()

        # reset whatever's left
        for model_proxy in QModelProxy.objects.filter(ontology=self):
            for property_proxy in model_proxy.property_proxies.all():
                property_proxy.reset()
                property_proxy.save()

        if recategorization_needed:
            msg = "Since you are re-registering an existing version, you will also have to re-register the corresponding categorization"
            if request:
                messages.add_message(request, messages.WARNING, msg)