Ejemplo n.º 1
0
    def evaluate(self):
        """
            Add this relation to the participating ends
        """
        try:
            left = self.namespace.get_type(self.left[0])
        except TypeNotFoundException as e:
            e.set_location(self.location)
            raise e

        if isinstance(left, Default):
            raise TypingException(
                self,
                "Can not define relation on a default constructor %s, use base type instead: %s " % (
                    left.name, left.get_entity().get_full_name())
            )

        if left.get_attribute_from_related(self.right[1]) is not None:
            raise DuplicateException(self, left.get_attribute_from_related(self.right[1]),
                                     ("Attribute name %s is already defined in %s, unable to define relationship")
                                     % (self.right[1], left.name))

        try:
            right = self.namespace.get_type(self.right[0])
        except TypeNotFoundException as e:
            e.set_location(self.location)
            raise e

        if isinstance(right, Default):
            raise TypingException(
                self,
                "Can not define relation on a default constructor %s, use base type instead: %s " % (
                    right.name, right.get_entity().get_full_name())
            )

        if right.get_attribute_from_related(self.left[1]) is not None:
            raise DuplicateException(self, right.get_attribute_from_related(self.left[1]),
                                     ("Attribute name %s is already defined in %s, unable to define relationship")
                                     % (self.left[1], right.name))

        if self.left[1] is not None:
            left_end = RelationAttribute(right, left, self.left[1])
            left_end.set_multiplicity(self.left[2])
            left_end.comment = self.comment
            self.copy_location(left_end)
        else:
            left_end = None

        if self.right[1] is not None:
            right_end = RelationAttribute(left, right, self.right[1])
            right_end.set_multiplicity(self.right[2])
            right_end.comment = self.comment
            self.copy_location(right_end)
        else:
            right_end = None

        if left_end is not None and right_end is not None:
            left_end.end = right_end
            right_end.end = left_end
Ejemplo n.º 2
0
    def add_to_index(self, instance: Instance) -> None:
        """
        Update indexes based on the instance and the attribute that has
        been set
        """
        attributes = {
            k: repr(v.get_value())
            for (k, v) in instance.slots.items() if v.is_ready()
        }
        # check if an index entry can be added
        for index_attributes in self.get_indices():
            index_ok = True
            key = []
            for attribute in index_attributes:
                if attribute not in attributes:
                    index_ok = False
                else:
                    key.append("%s=%s" % (attribute, attributes[attribute]))

            if index_ok:
                keys = ", ".join(key)

                if keys in self._index and self._index[keys] is not instance:
                    raise DuplicateException(
                        instance, self._index[keys],
                        "Duplicate key in index. %s" % keys)

                self._index[keys] = instance

                if keys in self.index_queue:
                    for x, stmt in self.index_queue[keys]:
                        x.set_value(instance, stmt.location)
                    self.index_queue.pop(keys)
Ejemplo n.º 3
0
 def __init__(self, items: typing.List[typing.Tuple[str, ReferenceStatement]]) -> None:
     ReferenceStatement.__init__(self, [x[1] for x in items])
     self.items = items
     seen = {}  # type: typing.Dict[str,ReferenceStatement]
     for x, v in items:
         if x in seen:
             raise DuplicateException(v, seen[x], "duplicate key in dict %s" % x)
         seen[x] = v
Ejemplo n.º 4
0
 def add_attribute(self, attribute: "Attribute") -> None:
     """
     Add an attribute to this entity. The attribute should not exist yet.
     """
     if attribute.name not in self._attributes:
         self._attributes[attribute.name] = attribute
     else:
         raise DuplicateException(self._attributes[attribute.name],
                                  attribute, "attribute already exists")
Ejemplo n.º 5
0
    def evaluate(self) -> None:
        """
            Evaluate this statement.
        """
        try:
            entity_type = self.type
            entity_type.comment = self.comment

            add_attributes = {}
            for attribute in self.attributes:
                attr_type = self.namespace.get_type(attribute.type)
                if not isinstance(attr_type, (Type, type)):
                    raise TypingException(self, "Attributes can only be a type. Entities need to be defined as relations.")

                attr_obj = Attribute(entity_type, attr_type, attribute.name, attribute.multi, attribute.nullable)
                attribute.copy_location(attr_obj)

                add_attributes[attribute.name] = attr_obj

                if attribute.default is not None:
                    entity_type.add_default_value(attribute.name, attribute.default)
                elif attribute.remove_default:
                    entity_type.add_default_value(attribute.name, None)

            if len(set(self.parents)) != len(self.parents):
                raise TypingException(self, "same parent defined twice")
            for parent in self.parents:
                parent_type = self.namespace.get_type(str(parent))
                if parent_type is self.type:
                    raise TypingException(self, "Entity can not be its own parent (%s) " % parent)
                if not isinstance(parent_type, Entity):
                    raise TypingException(self, "Parents of an entity need to be entities. "
                                          "Default constructors are not supported. %s is not an entity" % parent)

                entity_type.parent_entities.append(parent_type)
                parent_type.child_entities.append(entity_type)

            for parent_type in entity_type.get_all_parent_entities():
                for attr_name, other_attr in parent_type.attributes.items():
                    if attr_name not in add_attributes:
                        add_attributes[attr_name] = other_attr
                    else:
                        # allow compatible attributes
                        my_attr = add_attributes[attr_name]

                        if my_attr.type == other_attr.type:
                            add_attributes[attr_name] = other_attr
                        else:
                            raise DuplicateException(
                                my_attr, other_attr, "Incompatible attributes")
            # verify all attribute compatibility
        except TypeNotFoundException as e:
            e.set_statement(self)
            raise e
Ejemplo n.º 6
0
    def normalize(self) -> None:
        for attribute in self.__default_values.values():
            if attribute.default is not None:
                default_type: Type = attribute.type.get_type(self.namespace)
                try:
                    default_type.validate(attribute.default.as_constant())
                except RuntimeException as exception:
                    if exception.stmt is None or isinstance(
                            exception.stmt, Type):
                        exception.set_statement(attribute)
                        exception.location = attribute.location
                    raise exception

        # check for duplicate relations in parent entities
        for name, my_attribute in self.get_attributes().items():
            if isinstance(my_attribute,
                          inmanta.ast.attribute.RelationAttribute):
                for parent in self.parent_entities:
                    parent_attr = parent.get_attribute(name)
                    if parent_attr is not None:
                        raise DuplicateException(
                            my_attribute,
                            parent_attr,
                            f"Attribute name {name} is already defined in {parent_attr.entity.name},"
                            " unable to define relationship",
                        )

        for d in self.implementations:
            d.normalize()

        for i in self.implements:
            i.normalize()

        self.subc = [SubConstructor(self, i) for i in self.get_implements()]
        for sub in self.subc:
            sub.normalize()
Ejemplo n.º 7
0
 def get_double_defined_exception(
         self, other: "Namespaced") -> "DuplicateException":
     raise DuplicateException(
         self, other, "Implementation %s for type %s is already defined" %
         (self.get_full_name(), self.target_type))
Ejemplo n.º 8
0
 def get_double_defined_exception(
         self, other: "Namespaced") -> "DuplicateException":
     return DuplicateException(
         self, other,
         "Entity %s is already defined" % (self.get_full_name()))
Ejemplo n.º 9
0
    def execute(self, requires: Dict[object, object], resolver: Resolver,
                queue: QueueScheduler):
        """
        Evaluate this statement.
        """
        LOGGER.log(LOG_LEVEL_TRACE, "executing constructor for %s at %s",
                   self.class_type, self.location)

        # the type to construct
        type_class = self.type.get_entity()

        # kwargs
        kwarg_attrs: Dict[str, object] = {}
        for kwargs in self.wrapped_kwargs:
            for (k, v) in kwargs.execute(requires, resolver, queue):
                if k in self.attributes or k in kwarg_attrs:
                    raise RuntimeException(
                        self,
                        "The attribute %s is set twice in the constructor call of %s."
                        % (k, self.class_type))
                attribute = self.type.get_entity().get_attribute(k)
                if attribute is None:
                    raise TypingException(
                        self, "no attribute %s on type %s" %
                        (k, self.type.get_full_name()))
                kwarg_attrs[k] = v

        missing_attrs: List[str] = [
            attr for attr in self.required_kwargs if attr not in kwarg_attrs
        ]
        if missing_attrs:
            raise IndexAttributeMissingInConstructorException(
                self, type_class, missing_attrs)

        # Schedule all direct attributes for direct execution. The kwarg keys and the direct_attributes keys are disjoint
        # because a RuntimeException is raised above when they are not.
        direct_attributes: Dict[str, object] = {
            k: v.execute(requires, resolver, queue)
            for (k, v) in self._direct_attributes.items()
        }
        direct_attributes.update(kwarg_attrs)

        # Override defaults with kwargs. The kwarg keys and the indirect_attributes keys are disjoint because a RuntimeException
        # is raised above when they are not.
        indirect_attributes: Dict[str, ExpressionStatement] = {
            k: v
            for k, v in self._indirect_attributes.items()
            if k not in kwarg_attrs
        }

        # check if the instance already exists in the index (if there is one)
        instances: List[Instance] = []
        for index in type_class.get_indices():
            params = []
            for attr in index:
                params.append((attr, direct_attributes[attr]))

            obj: Optional[Instance] = type_class.lookup_index(params, self)

            if obj is not None:
                if obj.get_type().get_entity() != type_class:
                    raise DuplicateException(
                        self, obj, "Type found in index is not an exact match")
                instances.append(obj)

        graph: Optional[DataflowGraph] = resolver.dataflow_graph
        if len(instances) > 0:
            if graph is not None:
                graph.add_index_match(
                    chain(
                        [self.get_dataflow_node(graph)],
                        (i.instance_node
                         for i in instances if i.instance_node is not None),
                    ))
            # ensure that instances are all the same objects
            first = instances[0]
            for i in instances[1:]:
                if i != first:
                    raise Exception("Inconsistent indexes detected!")

            object_instance = first
            self.copy_location(object_instance)
            for k, v in direct_attributes.items():
                object_instance.set_attribute(k, v, self.location)
        else:
            # create the instance
            object_instance = type_class.get_instance(
                direct_attributes, resolver, queue, self.location,
                self.get_dataflow_node(graph) if graph is not None else None)

        # deferred execution for indirect attributes
        for attributename, valueexpression in indirect_attributes.items():
            var = object_instance.get_attribute(attributename)
            if var.is_multi():
                # gradual only for multi
                # to preserve order on lists used in attributes
                # while allowing gradual execution on relations
                reqs = valueexpression.requires_emit_gradual(
                    resolver, queue,
                    GradualSetAttributeHelper(self, object_instance,
                                              attributename, var))
            else:
                reqs = valueexpression.requires_emit(resolver, queue)
            SetAttributeHelper(queue, resolver, var, reqs, valueexpression,
                               self, object_instance, attributename)

        # generate an implementation
        for stmt in type_class.get_sub_constructor():
            stmt.emit(object_instance, queue)

        object_instance.trackers.append(queue.get_tracker())

        return object_instance
Ejemplo n.º 10
0
 def get_double_defined_exception(self, other: "NamedType") -> DuplicateException:
     return DuplicateException(self, other, "TypeConstraint %s is already defined" % (self.get_full_name()))
Ejemplo n.º 11
0
 def get_double_defined_exception(self, other: "NamedType") -> "DuplicateException":
     """produce an error message for this type"""
     raise DuplicateException(self, other, "Type %s is already defined" % (self.get_full_name()))
Ejemplo n.º 12
0
    def evaluate(self) -> None:
        """
        Add this relation to the participating ends
        """
        try:
            left = self.namespace.get_type(self.left[0])
        except TypeNotFoundException as e:
            e.set_location(self.location)
            raise e

        if isinstance(left, Default):
            raise TypingException(
                self,
                "Can not define relation on a default constructor %s, use base type instead: %s "
                % (left.name, left.get_entity().get_full_name()),
            )

        assert isinstance(left, Entity), "%s is not an entity" % left

        if left.get_attribute_from_related(str(self.right[1])) is not None:
            raise DuplicateException(
                self,
                left.get_attribute_from_related(str(self.right[1])),
                ("Attribute name %s is already defined in %s, unable to define relationship"
                 ) % (str(self.right[1]), left.name),
            )

        try:
            right = self.namespace.get_type(self.right[0])
        except TypeNotFoundException as e:
            e.set_location(self.location)
            raise e

        if isinstance(right, Default):
            raise TypingException(
                self,
                "Can not define relation on a default constructor %s, use base type instead: %s "
                % (right.name, right.get_entity().get_full_name()),
            )

        assert isinstance(right, Entity), "%s is not an entity" % right

        if right.get_attribute_from_related(str(self.left[1])) is not None:
            raise DuplicateException(
                self,
                right.get_attribute_from_related(str(self.left[1])),
                ("Attribute name %s is already defined in %s, unable to define relationship"
                 ) % (str(self.left[1]), right.name),
            )

        left_end: Optional[RelationAttribute]
        if self.left[1] is not None:
            left_end = RelationAttribute(right, left, str(self.left[1]),
                                         self.left[1].get_location())
            left_end.target_annotations = self.annotations
            left_end.set_multiplicity(self.left[2])
            left_end.comment = self.comment
        else:
            left_end = None

        right_end: Optional[RelationAttribute]
        if self.right[1] is not None:
            if right == left and str(self.left[1]) == str(self.right[1]):
                # relation is its own inverse
                right_end = left_end
            else:
                right_end = RelationAttribute(left, right, str(self.right[1]),
                                              self.right[1].get_location())
                right_end.source_annotations = self.annotations
                right_end.set_multiplicity(self.right[2])
                right_end.comment = self.comment
        else:
            right_end = None

        if left_end is not None and right_end is not None:
            left_end.end = right_end
            right_end.end = left_end
Ejemplo n.º 13
0
    def execute(self, requires: Dict[object, ResultVariable], resolver: Resolver, queue: QueueScheduler):
        """
            Evaluate this statement.
        """
        # the type to construct
        type_class = self.type.get_entity()

        # the attributes
        attributes = {k: v.execute(requires, resolver, queue) for (k, v) in self._direct_attributes.items()}

        for (k, v) in self.type.get_defaults().items():
            if(k not in attributes):
                attributes[k] = v.execute(requires, resolver, queue)

        for (k, v) in type_class.get_default_values().items():
            if(k not in attributes):
                attributes[k] = v.execute(requires, resolver, queue)

        # check if the instance already exists in the index (if there is one)
        instances = []
        for index in type_class.get_indices():
            params = []
            for attr in index:
                params.append((attr, attributes[attr]))

            obj = type_class.lookup_index(params, self)

            if obj is not None:
                if obj.get_type().get_entity() != type_class:
                    raise DuplicateException(self, object, "Type found in index is not an exact match")
                instances.append(obj)

        if len(instances) > 0:
            # ensure that instances are all the same objects
            first = instances[0]
            for i in instances[1:]:
                if i != first:
                    raise Exception("Inconsistent indexes detected!")

            object_instance = first
            for k, v in attributes.items():
                object_instance.set_attribute(k, v, self.location)

        else:
            # create the instance
            object_instance = type_class.get_instance(attributes, resolver, queue, self.location)
            self.copy_location(object_instance)

        # deferred execution for indirect attributes
        for attributename, valueexpression in self._indirect_attributes.items():
            var = object_instance.get_attribute(attributename)
            reqs = valueexpression.requires_emit_gradual(resolver, queue, var)
            SetAttributeHelper(queue, resolver, var, reqs, valueexpression, self, object_instance)

        # add anonymous implementations
        if self.implemented:
            # generate an import for the module
            raise Exception("don't know this feature")

        else:
            # generate an implementation
            for stmt in type_class.get_sub_constructor():
                stmt.emit(object_instance, queue)

        if self.register:
            raise Exception("don't know this feature")

        object_instance.trackers.append(queue.get_tracker())

        return object_instance