def get_message_offset(msg, base_interval=None): """Return deprecated message offset, or None. TODO - this function can be deleted once the deprecated cycle point offset placeholders are removed from cylc (see GitHub #1761). """ offset = None global warned # cylc-5 [T+n] message offset - DEPRECATED m = BCOMPAT_MSG_RE_C5.match(msg) if m: if not warned: print >> sys.stderr, DEPRECN_WARN_TMPL % msg warned = True prefix, signed_offset, sign, offset, suffix = m.groups() if signed_offset is not None: offset = base_interval.get_inferred_child( signed_offset) else: # cylc-6 [<interval>] message offset - DEPRECATED n = BCOMPAT_MSG_RE_C6.match(msg) if n: if not warned: print >> sys.stderr, DEPRECN_WARN_TMPL % msg warned = True prefix, signed_offset, sign, offset, suffix = n.groups() if offset: offset = get_interval(signed_offset) else: offset = get_interval_cls().get_null() # else: Plain message, no offset. return offset
def get_message_offset(msg, base_interval=None): """Return deprecated message offset, or None. TODO - this function can be deleted once the deprecated cycle point offset placeholders are removed from cylc (see GitHub #1761). """ offset = None global warned # cylc-5 [T+n] message offset - DEPRECATED m = BCOMPAT_MSG_RE_C5.match(msg) if m: if not warned: print >> sys.stderr, DEPRECN_WARN_TMPL % msg warned = True prefix, signed_offset, sign, offset, suffix = m.groups() if signed_offset is not None: offset = base_interval.get_inferred_child(signed_offset) else: # cylc-6 [<interval>] message offset - DEPRECATED n = BCOMPAT_MSG_RE_C6.match(msg) if n: if not warned: print >> sys.stderr, DEPRECN_WARN_TMPL % msg warned = True prefix, signed_offset, sign, offset, suffix = n.groups() if offset: offset = get_interval(signed_offset) else: offset = get_interval_cls().get_null() # else: Plain message, no offset. return offset
def set_runahead(self, interval=None): if isinstance(interval, int) or isinstance(interval, basestring): # The unit is assumed to be hours (backwards compatibility). interval = str(interval) interval_cls = get_interval_cls() if interval_cls.TYPE == ISO8601_CYCLING_TYPE: interval = get_interval("PT%sH" % interval) else: interval = get_interval(interval) if interval is None: # No limit self.log.warning("setting NO custom runahead limit") self.custom_runahead_limit = None else: self.log.info("setting custom runahead limit to %s" % interval) self.custom_runahead_limit = interval self.release_runahead_tasks()
def __init__(self, task_name, qualifier=None, graph_offset_string=None, cycle_point=None, suicide=False, outputs={}, base_interval=None): self.task_name = task_name self.suicide = suicide self.graph_offset_string = graph_offset_string self.cycle_point = cycle_point self.message = None self.message_offset = None self.builtin = None qualifier = qualifier or "succeeded" # Built-in trigger? try: self.builtin = task_state.get_legal_trigger_state(qualifier) except TaskStateError: pass else: return # Message trigger? try: msg = outputs[qualifier] except KeyError: raise TriggerError, ("ERROR: undefined trigger qualifier: %s:%s" % (task_name, qualifier)) else: # Back compat for [T+n] in message string. m = re.match(BACK_COMPAT_MSG_RE, msg) msg_offset = None if m: prefix, signed_offset, sign, offset, suffix = m.groups() if offset: msg_offset = base_interval.get_inferred_child( signed_offset) else: msg_offset = get_interval_cls().get_null() else: n = re.match(MSG_RE, msg) if n: prefix, signed_offset, sign, offset, suffix = n.groups() if offset: msg_offset = get_interval(signed_offset) else: msg_offset = get_interval_cls().get_null() else: raise TriggerError, ( "ERROR: undefined trigger qualifier: %s:%s" % (task_name, qualifier)) self.message = msg self.message_offset = msg_offset
def _get_offset(self, offset=None): """Return and cache the standardised offset string.""" if offset not in self._offsets: if offset: res = get_interval(offset).standardise() else: res = get_interval_cls().get_null_offset() self._offsets[offset] = str(res) return self._offsets[offset]
def __init__( self, task_name, qualifier=None, graph_offset_string=None, cycle_point=None, suicide=False, outputs={}, base_interval=None): self.task_name = task_name self.suicide = suicide self.graph_offset_string = graph_offset_string self.cycle_point = cycle_point self.message = None self.message_offset = None self.builtin = None qualifier = qualifier or "succeeded" # Built-in trigger? try: self.builtin = task_state.get_legal_trigger_state(qualifier) except TaskStateError: pass else: return # Message trigger? try: msg = outputs[qualifier] except KeyError: raise TriggerError, ( "ERROR: undefined trigger qualifier: %s:%s" % ( task_name, qualifier) ) else: # Back compat for [T+n] in message string. m = re.match(BACK_COMPAT_MSG_RE, msg) msg_offset = None if m: prefix, signed_offset, sign, offset, suffix = m.groups() if offset: msg_offset = base_interval.get_inferred_child(signed_offset) else: msg_offset = get_interval_cls().get_null() else: n = re.match(MSG_RE, msg) if n: prefix, signed_offset, sign, offset, suffix = n.groups() if offset: msg_offset = get_interval(signed_offset) else: msg_offset = get_interval_cls().get_null() else: raise TriggerError, ( "ERROR: undefined trigger qualifier: %s:%s" % ( task_name, qualifier) ) self.message = msg self.message_offset = msg_offset
def get_cleanup_cutoff_point(cls, my_point, offset_sequence_tuples): """Extract the max dependent cycle point for this point.""" if not offset_sequence_tuples: # This task does not have dependent tasks at other cycles. return my_point cutoff_points = [] for offset_string, sequence in offset_sequence_tuples: if offset_string is None: # This indicates a dependency that lasts for the whole run. return None if sequence is None: # This indicates a simple offset interval such as [-PT6H]. cutoff_points.append( my_point - get_interval(offset_string)) continue if is_offset_absolute(offset_string): stop_point = sequence.get_stop_point() if stop_point: # Stop point of the sequence is a good cutoff point for an # absolute "offset" cutoff_points.append(stop_point) continue else: # The dependency lasts for the whole run. return None # This is a complicated offset like [02T00-P1W]. dependent_point = sequence.get_start_point() my_cutoff_point = None while dependent_point is not None: # TODO: Is it realistically possible to hang in this loop? target_point = ( get_point_relative(offset_string, dependent_point)) if target_point > my_point: # Assume monotonic (target_point can never jump back). break if target_point == my_point: # We have found a dependent_point for my_point. my_cutoff_point = dependent_point dependent_point = sequence.get_next_point_on_sequence( dependent_point) if my_cutoff_point: # Choose the largest of the dependent points. cutoff_points.append(my_cutoff_point) if cutoff_points: max_cutoff_point = max(cutoff_points) if max_cutoff_point < my_point: # This is caused by future triggers - default to my_point. return my_point return max_cutoff_point # There aren't any dependent tasks in other cycles for my_point. return my_point
def get_cleanup_cutoff_point(self, point): """Extract the max dependent cycle point for this point.""" if not self.intercycle_offsets: # This task does not have dependent tasks at other cycles. return point cutoff_points = [] for offset_string, sequence in self.intercycle_offsets: if offset_string is None: # This indicates a dependency that lasts for the whole run. return None if sequence is None: # This indicates a simple offset interval such as [-PT6H]. cutoff_points.append(point - get_interval(offset_string)) continue if is_offset_absolute(offset_string): stop_point = sequence.get_stop_point() if stop_point: # Stop point of the sequence is a good cutoff point for an # absolute "offset" cutoff_points.append(stop_point) continue else: # The dependency lasts for the whole run. return None # This is a complicated offset like [02T00-P1W]. dependent_point = sequence.get_start_point() my_cutoff_point = None while dependent_point is not None: # TODO: Is it realistically possible to hang in this loop? target_point = (get_point_relative(offset_string, dependent_point)) if target_point > point: # Assume monotonic (target_point can never jump back). break if target_point == point: # We have found a dependent_point for point. my_cutoff_point = dependent_point dependent_point = sequence.get_next_point_on_sequence( dependent_point) if my_cutoff_point: # Choose the largest of the dependent points. cutoff_points.append(my_cutoff_point) if cutoff_points: max_cutoff_point = max(cutoff_points) if max_cutoff_point < point: # This is caused by future triggers - default to point. return point return max_cutoff_point # There aren't any dependent tasks in other cycles for point. return point
def get_cleanup_cutoff_point(cls, my_point, offset_sequence_tuples): """Extract the max dependent cycle point for this point.""" if not offset_sequence_tuples: # This task does not have dependent tasks at other cycles. return my_point cutoff_points = [] for offset_string, sequence in offset_sequence_tuples: if offset_string is None: # This indicates a dependency that lasts for the whole run. return None if sequence is None: # This indicates a simple offset interval such as [-PT6H]. cutoff_points.append(my_point - get_interval(offset_string)) continue # This is a complicated offset like [02T00-P1W]. dependent_point = sequence.get_start_point() matching_dependent_points = [] while dependent_point is not None: # TODO: Is it realistically possible to hang in this loop? target_point = (get_point_relative(offset_string, dependent_point)) if target_point > my_point: # Assume monotonic (target_point can never jump back). break if target_point == my_point: # We have found a dependent_point for my_point. matching_dependent_points.append(dependent_point) dependent_point = sequence.get_next_point_on_sequence( dependent_point) if matching_dependent_points: # Choose the largest of the dependent points. cutoff_points.append(matching_dependent_points[-1]) if cutoff_points: max_cutoff_point = max(cutoff_points) if max_cutoff_point < my_point: # This is caused by future triggers - default to my_point. return my_point return max_cutoff_point # There aren't any dependent tasks in other cycles for my_point. return my_point
def __init__(self, node, base_interval=None): node_in = node # Get task name and properties from a graph node name. # Graph node name is task name optionally followed by: # - output label: foo:m1 # - intercycle dependence: foo[T-6] # These may be combined: foo[T-6]:m1 # Task may be defined at initial cycle point: foo[^] # or relative to initial cycle point: foo[^+P1D] self.offset_is_from_ict = False self.offset_is_irregular = False self.is_absolute = False m = re.match(NODE_ISO_ICT_RE, node) if m: # node looks like foo[^], foo[^-P4D], foo[^]:fail, etc. self.is_absolute = True name, offset_string, outp = m.groups() self.offset_is_from_ict = True sign = "" prev_format = False # Can't always set syntax here, as we use [^] for backwards comp. else: m = re.match(NODE_ISO_RE, node) if m: # node looks like foo, foo:fail, foo[-PT6H], foo[-P4D]:fail... name, offset_string, outp = m.groups() sign = "" prev_format = False else: raise GraphNodeError('Illegal graph node: ' + node) if outp: self.special_output = True self.output = outp[1:] # strip ':' else: self.special_output = False self.output = None if name: self.name = name else: raise GraphNodeError('Illegal graph node: ' + node) if self.offset_is_from_ict and not offset_string: offset_string = str(get_interval_cls().get_null_offset()) if offset_string: self.intercycle = True if prev_format: self.offset_string = str( base_interval.get_inferred_child(offset_string)) else: if IRREGULAR_OFFSET_RE.search(offset_string): self.offset_string = offset_string self.offset_is_irregular = True else: self.offset_string = str( (get_interval(offset_string)).standardise()) else: self.intercycle = False self.offset_string = None
def __init__(self, node, base_interval=None): node_in = node # Get task name and properties from a graph node name. # Graph node name is task name optionally followed by: # - output label: foo:m1 # - intercycle dependence: foo[T-6] # These may be combined: foo[T-6]:m1 # Task may be defined at initial cycle point: foo[^] # or relative to initial cycle point: foo[^+P1D] self.offset_is_from_ict = False self.offset_is_irregular = False self.is_absolute = False m = re.match(NODE_ISO_ICT_RE, node) if m: # node looks like foo[^], foo[^-P4D], foo[^]:fail, etc. self.is_absolute = True name, offset_string, outp = m.groups() self.offset_is_from_ict = True sign = "" prev_format = False # Can't always set syntax here, as we use [^] for backwards comp. if offset_string: set_syntax_version( VERSION_NEW, "graphnode: %s: ISO 8601 offset" % node) else: m = re.match(NODE_ISO_RE, node) if m: # node looks like foo, foo:fail, foo[-PT6H], foo[-P4D]:fail... name, offset_string, outp = m.groups() sign = "" prev_format = False if offset_string: set_syntax_version( VERSION_NEW, "graphnode: %s: ISO 8601 offset" % node) else: m = re.match(NODE_PREV_RE, node) if not m: raise GraphNodeError('Illegal graph node: ' + node) # node looks like foo[T-6], foo[T-12]:fail... name, sign, offset_string, outp = m.groups() if sign and offset_string: offset_string = sign + offset_string prev_format = True set_syntax_version( VERSION_PREV, "graphnode %s: old-style offset" % node ) if outp: self.special_output = True self.output = outp[1:] # strip ':' else: self.special_output = False self.output = None if name: self.name = name else: raise GraphNodeError('Illegal graph node: ' + node) if self.offset_is_from_ict and not offset_string: offset_string = str(get_interval_cls().get_null_offset()) if offset_string: self.intercycle = True if prev_format: self.offset_string = str( base_interval.get_inferred_child(offset_string)) else: if IRREGULAR_OFFSET_RE.search(offset_string): self.offset_string = offset_string self.offset_is_irregular = True else: self.offset_string = str( (get_interval(offset_string)).standardise()) else: self.intercycle = False self.offset_string = None