Beispiel #1
0
 def create_new_flow(self):
   # don't repeat the actions from create_new_element() !
   if self.title is None:
     self.flow_model = FlowModel(element = self.element_model)
   else:
     self.flow_model = FlowModel(element = self.element_model, title = self.title)
   self.flow_model.save()
Beispiel #2
0
class Flow(Element):
  class_name = "flow"
  
  def __init__(self, title = None, flow_id = None, element_model = None):
    self.elements = []
    self.element_groups = []
    if (flow_id is None) and (element_model is None):
      # creating a new object : first create the Element(), then create a new flow
      super(Flow, self).__init__(title = title)
      self.create_new_flow()
    else:
      # loading an existing object : first get the element_model, then load the element from DB, then load the flow from DB
      if (element_model is None):
        # assume flow_id is not None
        # get flow_model and element_model from flow_id
        flow_model = FlowModel.objects.get(pk = flow_id)
        element_model = flow_model.element
      else:
        # we got element_model, get flow_model from it
        flow_model = element_model.flowmodel
        
      super(Flow, self).__init__(title = title, element_model = element_model)
        
      self.load_flow_from_database(flow_model)
        
  def create_new_flow(self):
    # don't repeat the actions from create_new_element() !
    if self.title is None:
      self.flow_model = FlowModel(element = self.element_model)
    else:
      self.flow_model = FlowModel(element = self.element_model, title = self.title)
    self.flow_model.save()
    
  def load_flow_from_database(self, flow_model = None):
    self.flow_model = flow_model
    self.title = self.flow_model.title
    for element_model in self.flow_model.elementmodel_set.all():
      specific_class = get_class_for_element_type(element_model.class_name)
      element = specific_class(element_model = element_model)
      self.add_element(element)
      element.find_and_set_group_update_grouplist(self.element_groups)
    
    for element in self.elements:
      if not(isinstance(element, Connection)):
        continue
      
      src_element_id = element.connection_model.src_element.id
      dst_element_id = element.connection_model.dst_element.id
      src_element = self.get_element(element_id = src_element_id)
      dst_element = self.get_element(element_id = dst_element_id)
      src = src_element.get_connector(element.connection_model.src_connector)
      dst = dst_element.get_connector(element.connection_model.dst_connector)
      element.set_src_dst(src, dst)
    
  @classmethod
  def get_all_saved_flows(cls):
    return FlowModel.objects.all()
    
  def get_id(self):
    return self.element_model.id
  
  def add_element(self, element):
    element.set_flow(self)
    self.elements.append(element)
    
    if (type(element) == InputData) and not(element.title is None):
      self.input_connectors.append(element.data_in)
      setattr(self, element.title, element.data_in)
    
    if (type(element) == OutputData) and not(element.title is None):
      self.output_connectors.append(element.data_out)
      setattr(self, element.title, element.data_out)
  
  def get_element(self, title = None, element_id = None):
    if element_id is not None:
      for element in self.elements:
        if element.element_model.id == element_id:
          return element
        if isinstance(element, Flow):
          try:
            return element.get_element(element_id = element_id)
          except ElementNotFoundError:
            pass
      raise ElementNotFoundError("Could not find element with id == %d" % (element_id))
          
    if title is not None:
      for element in self.elements:
        if element.title == title:
          return element
      raise ElementNotFoundError("Could not find element with title == %s" % (title))
  
    raise ValueError("Atleast title or element_id should be provided")
  
  def get_num_elements(self):
    return len(self.elements)
  
  def remove_element(self, element):
    # invalidate all the output connectors of this element + everything in this flow that depends on them
    for invalid_connector in element.output_connectors:
      self.invalidate_chain(invalid_connector)
    
    # Remove the element from this flow object
    self.elements.remove(element)
    
    # Remove the linked connections from this flow object
    # We need to iterate over a copy of self.elements[], because items will be removed from it
    for connection in self.elements[:]:
      if not(isinstance(connection, Connection)):
        continue
      if connection.dst in element.input_connectors:
        self.disconnect(connection)
        continue
      if connection.src in element.output_connectors:
        self.disconnect(connection)
        continue
      
    # Remove the element from the database
    # The database will automatically be updated to also remove the connections linked to this element
    element.delete()
    
  def connect(self, src, dst, title = None):
    for element in self.elements:
      if not(isinstance(element, Connection)):
        continue
      if (element.dst != dst):
        continue
      self.disconnect(element)
      break
      
    connection = Connection(title = title)
    connection.set_flow(self)
    connection.set_src_dst(src, dst)
    self.elements.append(connection)
    return connection
  
  def disconnect(self, connection):
    self.elements.remove(connection)
    needs_invalidate = connection.dst.default_needs_invalidate()
    if needs_invalidate:
      self.invalidate_chain(connection.dst)
    connection.dst.default()  # need to set default *after* invalidate()
    connection.delete()
  
  def invalidate_chain(self, invalid_connector):
    invalid_connector.invalidate_connector()
    for element in self.elements:
      if invalid_connector in element.input_connectors:
        # only return connectors which were still valid and are now made invalid
        new_invalid_connectors = element.invalidate_element(invalid_connector)
        for new_invalid_connector in new_invalid_connectors:
          self.invalidate_chain(new_invalid_connector)
  
  # extend element.invalidate_element() in case of element == Flow()
  # we need to also invalidate the internal flow, not just the output connectors
  # at the end, we need to return the result of element.invalidate_element() 
  # which is the list of output connectors that were invalidated
  def invalidate_element(self, invalid_connector):
    result = super(Flow, self).invalidate_element(invalid_connector)
    self.invalidate_chain(invalid_connector)
    return result
  
  def run(self, iteration = 0, debug = False):
    if debug:
      print
      print self.title, ":: run() :: iteration", iteration
      print
    
    elements_done = 0
    for element in self.elements:
      if element.is_ready() and not element.is_done():
        if debug:
          print self.title, "  execute element :", element
        element.run_or_block(debug = debug)
        elements_done += 1

    if debug:
      print
      print self.title, "  elements_done =", elements_done
      print
    
    if elements_done == 0:
      return True
    
    return self.run(iteration + 1, debug = debug)
  

  def debug_state(self):
    print "==== FLOW : %s ====" % self.title
    super(Flow, self).debug_state()
    for element in self.elements:
      element.debug_state()
    print "==== ===="