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
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)
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
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")
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
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()
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))
def get_double_defined_exception( self, other: "Namespaced") -> "DuplicateException": return DuplicateException( self, other, "Entity %s is already defined" % (self.get_full_name()))
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
def get_double_defined_exception(self, other: "NamedType") -> DuplicateException: return DuplicateException(self, other, "TypeConstraint %s is already defined" % (self.get_full_name()))
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()))
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
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