def _coerce_cycletime(value, keys, _): """Coerce value to a cycle point.""" if not value: return None if value == "now": # Handle this later in config.py when the suite UTC mode is known. return value value = _strip_and_unquote(keys, value) if re.match(r"\d+$", value): # Could be an old date-time cycle point format, or integer format. return value if value.startswith("-") or value.startswith("+"): # We don't know the value given for num expanded year digits... for i in range(1, 101): parser = TimePointParser(num_expanded_year_digits=i) try: parser.parse(value) except ValueError: continue return value raise IllegalValueError("cycle point", keys, value) parser = TimePointParser() try: parser.parse(value) except ValueError: raise IllegalValueError("cycle point", keys, value) set_syntax_version(VERSION_NEW, "cycle point: %s" % itemstr(keys[:-1], keys[-1], value)) return value
def coerce_interval(value, keys, args, back_comp_unit_factor=1, check_syntax_version=True): """Coerce an ISO 8601 interval (or number: back-comp) into seconds.""" value = _strip_and_unquote(keys, value) try: backwards_compat_value = float(value) * back_comp_unit_factor except (TypeError, ValueError): pass else: if check_syntax_version: set_syntax_version(VERSION_PREV, "integer interval: %s" % itemstr( keys[:-1], keys[-1], value)) return backwards_compat_value try: interval = interval_parser.parse(value) except ValueError: raise IllegalValueError("ISO 8601 interval", keys, value) if check_syntax_version: try: set_syntax_version(VERSION_NEW, "ISO 8601 interval: %s" % itemstr( keys[:-1], keys[-1], value)) except SyntaxVersionError as exc: raise Exception(str(exc)) days, seconds = interval.get_days_and_seconds() seconds += days * Calendar.default().SECONDS_IN_DAY return seconds
def _coerce_cycletime_format( value, keys, args ): """Coerce value to a cycle point format (either CCYYMM... or %Y%m...).""" value = _strip_and_unquote( keys, value ) set_syntax_version(VERSION_NEW, "use of [cylc]cycle point format", exc_class=IllegalValueError, exc_args=("cycle point format", keys, value)) test_timepoint = TimePoint(year=2001, month_of_year=3, day_of_month=1, hour_of_day=4, minute_of_hour=30, second_of_minute=54) if "/" in value or ":" in value: raise IllegalValueError("cycle point format", keys, value) if "%" in value: try: TimePointDumper().strftime(test_timepoint, value) except ValueError: raise IllegalValueError("cycle point format", keys, value) return value if "X" in value: for i in range(1, 101): dumper = TimePointDumper(num_expanded_year_digits=i) try: dumper.dump(test_timepoint, value) except ValueError: continue return value raise IllegalValueError("cycle point format", keys, value) dumper = TimePointDumper() try: dumper.dump(test_timepoint, value) except ValueError: raise IllegalValueError("cycle point format", keys, value) return value
def _coerce_cycletime_time_zone(value, keys, _): """Coerce value to a cycle point time zone format - Z, +13, -0800...""" value = _strip_and_unquote(keys, value) if not value: return None try: set_syntax_version(VERSION_NEW, "use of [cylc]cycle point time zone format") except SyntaxVersionError: raise IllegalValueError("cycle point time zone format", keys, value) test_timepoint = TimePoint(year=2001, month_of_year=3, day_of_month=1, hour_of_day=4, minute_of_hour=30, second_of_minute=54) dumper = TimePointDumper() test_timepoint_string = dumper.dump(test_timepoint, "CCYYMMDDThhmmss") test_timepoint_string += value parser = TimePointParser(allow_only_basic=True) try: parser.parse(test_timepoint_string) except ValueError: raise IllegalValueError("cycle point time zone format", keys, value) return value
def coerce_interval(value, keys, _, back_comp_unit_factor=1, check_syntax_version=True): """Coerce an ISO 8601 interval (or number: back-comp) into seconds.""" value = _strip_and_unquote(keys, value) if not value: # Allow explicit empty values. return None try: backwards_compat_value = float(value) * back_comp_unit_factor except (TypeError, ValueError): pass else: if check_syntax_version: set_syntax_version( VERSION_PREV, "integer interval: %s" % itemstr(keys[:-1], keys[-1], value)) return DurationFloat(backwards_compat_value) try: interval = DURATION_PARSER.parse(value) except ValueError: raise IllegalValueError("ISO 8601 interval", keys, value) if check_syntax_version: set_syntax_version( VERSION_NEW, "ISO 8601 interval: %s" % itemstr(keys[:-1], keys[-1], value)) days, seconds = interval.get_days_and_seconds() return DurationFloat(days * CALENDAR.SECONDS_IN_DAY + seconds)
def _coerce_cycletime( value, keys, args ): """Coerce value to a cycle point.""" value = _strip_and_unquote( keys, value ) if re.match(r"\d+$", value): # Could be an old date-time cycle point format, or integer format. return value if value.startswith("-") or value.startswith("+"): # We don't know the value given for num expanded year digits... for i in range(1, 101): parser = TimePointParser(num_expanded_year_digits=i) try: parser.parse(value) except ValueError: continue return value raise IllegalValueError("cycle point", keys, value) parser = TimePointParser() try: parser.parse(value) except ValueError: raise IllegalValueError("cycle point", keys, value) set_syntax_version(VERSION_NEW, "cycle point: %s" % itemstr( keys[:-1], keys[-1], value)) return value
def _point_parse(point_string): """Parse a point_string into a proper TimePoint object.""" if "%" in SuiteSpecifics.DUMP_FORMAT: # Includes prev-format point strings. try: point = SuiteSpecifics.point_parser.strptime( point_string, SuiteSpecifics.DUMP_FORMAT) except ValueError as e: strptime_string = _get_old_strptime_format(point_string) if strptime_string is not None: return SuiteSpecifics.point_parser.strptime( point_string, strptime_string) else: return point # Attempt to parse it in ISO 8601 format then... try: point = SuiteSpecifics.point_parser.parse(point_string) # Fail? return point except ValueError: strptime_string = _get_old_strptime_format(point_string) if strptime_string is None: raise set_syntax_version( VERSION_PREV, "non-ISO-8601-compatible cycle point: %s" % point_string ) return SuiteSpecifics.point_parser.strptime( point_string, strptime_string)
def _point_parse(point_string): """Parse a point_string into a proper TimePoint object.""" if "%" in SuiteSpecifics.DUMP_FORMAT: # Includes prev-format point strings. try: point = SuiteSpecifics.point_parser.strptime( point_string, SuiteSpecifics.DUMP_FORMAT) except ValueError as e: strptime_string = _get_old_strptime_format(point_string) if strptime_string is not None: return SuiteSpecifics.point_parser.strptime( point_string, strptime_string) else: return point # Attempt to parse it in ISO 8601 format then... try: point = SuiteSpecifics.point_parser.parse(point_string) # Fail? return point except ValueError: strptime_string = _get_old_strptime_format(point_string) if strptime_string is None: raise set_syntax_version( VERSION_PREV, "non-ISO-8601-compatible cycle point: %s" % point_string) return SuiteSpecifics.point_parser.strptime(point_string, strptime_string)
def coerce_interval(value, keys, args, back_comp_unit_factor=1, check_syntax_version=True): """Coerce an ISO 8601 interval (or number: back-comp) into seconds.""" value = _strip_and_unquote(keys, value) try: backwards_compat_value = float(value) * back_comp_unit_factor except (TypeError, ValueError): pass else: if check_syntax_version: set_syntax_version( VERSION_PREV, "integer interval: %s" % itemstr(keys[:-1], keys[-1], value)) return backwards_compat_value try: interval = interval_parser.parse(value) except ValueError: raise IllegalValueError("ISO 8601 interval", keys, value) if check_syntax_version: try: set_syntax_version( VERSION_NEW, "ISO 8601 interval: %s" % itemstr(keys[:-1], keys[-1], value)) except SyntaxVersionError as exc: raise Exception(str(exc)) days, seconds = interval.get_days_and_seconds() seconds += days * Calendar.default().SECONDS_IN_DAY return seconds
def _coerce_cycletime_time_zone( value, keys, args ): """Coerce value to a cycle point time zone format - Z, +13, -0800...""" value = _strip_and_unquote( keys, value ) set_syntax_version(VERSION_NEW, "use of [cylc]cycle point time zone format", exc_class=IllegalValueError, exc_args=("cycle point time zone format", keys, value)) test_timepoint = TimePoint(year=2001, month_of_year=3, day_of_month=1, hour_of_day=4, minute_of_hour=30, second_of_minute=54) dumper = TimePointDumper() test_timepoint_string = dumper.dump(test_timepoint, "CCYYMMDDThhmmss") test_timepoint_string += value parser = TimePointParser(allow_only_basic=True) try: parser.parse(test_timepoint_string) except ValueError: raise IllegalValueError("cycle point time zone format", keys, value) return value
def _coerce_cycleinterval(value, keys, _): """Coerce value to a cycle interval.""" if not value: return None value = _strip_and_unquote(keys, value) if value.isdigit(): # Old runahead limit format. set_syntax_version( VERSION_PREV, "integer interval for %s" % itemstr(keys[:-1], keys[-1], value)) return value if REC_INTEGER_INTERVAL.match(value): # New integer cycling format. set_syntax_version( VERSION_NEW, "integer interval for %s" % itemstr(keys[:-1], keys[-1], value)) return value parser = DurationParser() try: parser.parse(value) except ValueError: raise IllegalValueError("interval", keys, value) set_syntax_version( VERSION_NEW, "ISO 8601 interval for %s" % itemstr(keys[:-1], keys[-1], value)) return value
def _coerce_cycleinterval(value, keys, _): """Coerce value to a cycle interval.""" if not value: return None value = _strip_and_unquote(keys, value) if value.isdigit(): # Old runahead limit format. set_syntax_version(VERSION_PREV, "integer interval for %s" % itemstr( keys[:-1], keys[-1], value)) return value if REC_INTEGER_INTERVAL.match(value): # New integer cycling format. set_syntax_version(VERSION_NEW, "integer interval for %s" % itemstr( keys[:-1], keys[-1], value)) return value parser = DurationParser() try: parser.parse(value) except ValueError: raise IllegalValueError("interval", keys, value) set_syntax_version(VERSION_NEW, "ISO 8601 interval for %s" % itemstr( keys[:-1], keys[-1], value)) return value
def _coerce_cycletime_format(value, keys, _): """Coerce value to a cycle point format (either CCYYMM... or %Y%m...).""" value = _strip_and_unquote(keys, value) if not value: return None try: set_syntax_version(VERSION_NEW, "use of [cylc]cycle point format") except SyntaxVersionError: raise IllegalValueError("cycle point format", keys, value) test_timepoint = TimePoint(year=2001, month_of_year=3, day_of_month=1, hour_of_day=4, minute_of_hour=30, second_of_minute=54) if "/" in value: raise IllegalValueError("cycle point format", keys, value) if "%" in value: try: TimePointDumper().strftime(test_timepoint, value) except ValueError: raise IllegalValueError("cycle point format", keys, value) return value if "X" in value: for i in range(1, 101): dumper = TimePointDumper(num_expanded_year_digits=i) try: dumper.dump(test_timepoint, value) except ValueError: continue return value raise IllegalValueError("cycle point format", keys, value) dumper = TimePointDumper() try: dumper.dump(test_timepoint, value) except ValueError: raise IllegalValueError("cycle point format", keys, value) return value
def init_from_cfg(cfg): """Initialise global variables (yuk) based on the configuration.""" num_expanded_year_digits = cfg['cylc'][ 'cycle point num expanded year digits'] time_zone = cfg['cylc']['cycle point time zone'] custom_dump_format = cfg['cylc']['cycle point format'] initial_cycle_point = cfg['scheduling']['initial cycle point'] final_cycle_point = cfg['scheduling']['final cycle point'] assume_utc = cfg['cylc']['UTC mode'] cycling_mode = cfg['scheduling']['cycling mode'] # Detect (date-time) previous-format cycle point usage. has_prev_format_cycle_point = ( (initial_cycle_point is not None and PREV_DATE_TIME_REC.search(initial_cycle_point)) or (final_cycle_point is not None and PREV_DATE_TIME_REC.search(final_cycle_point)) ) if (has_prev_format_cycle_point and custom_dump_format != PREV_DATE_TIME_FORMAT): set_syntax_version( VERSION_PREV, "initial/final cycle point format: CCYYMMDDhh" ) # Detect (date-time) ISO 8601-format cycle point usage. has_new_format_cycle_point = ( (initial_cycle_point is not None and NEW_DATE_TIME_REC.search(initial_cycle_point)) or (final_cycle_point is not None and NEW_DATE_TIME_REC.search(final_cycle_point)) ) if has_new_format_cycle_point: set_syntax_version( VERSION_NEW, "initial/final cycle point format: non-numeric (ISO 8601?)" ) # Loop over all dependency sub-sections and detect cycler syntax versions. dep_sections = list(cfg['scheduling']['dependencies']) while dep_sections: dep_section = dep_sections.pop(0) if re.search("(?![^(]+\)),", dep_section): dep_sections.extend( [i.strip() for i in re.split("(?![^(]+\)),", dep_section)]) continue if dep_section == "graph": if cfg['scheduling']['dependencies']['graph']: # Using async graph in date-time cycling. set_syntax_version( VERSION_PREV, "[scheduling][[dependencies]]graph: mixed with " + "date-time cycling" ) custom_dump_format = PREV_DATE_TIME_FORMAT num_expanded_year_digits = 0 continue if convert_old_cycler_syntax(dep_section, only_detect_old=True): # Detected prev-format (old) syntax. set_syntax_version( VERSION_PREV, "[scheduling][[dependencies]][[[%s]]]: old-style cycling" % dep_section ) custom_dump_format = PREV_DATE_TIME_FORMAT num_expanded_year_digits = 0 else: # Detected new-style syntax. set_syntax_version( VERSION_NEW, ("[scheduling][[dependencies]][[[%s]]]: " % dep_section) + "ISO 8601-style cycling" ) init( num_expanded_year_digits=num_expanded_year_digits, custom_dump_format=custom_dump_format, time_zone=time_zone, assume_utc=assume_utc, cycling_mode=cycling_mode )
def init_from_cfg(cfg): """Initialise global variables (yuk) based on the configuration.""" num_expanded_year_digits = cfg['cylc'][ 'cycle point num expanded year digits'] time_zone = cfg['cylc']['cycle point time zone'] custom_dump_format = cfg['cylc']['cycle point format'] initial_cycle_point = cfg['scheduling']['initial cycle point'] final_cycle_point = cfg['scheduling']['final cycle point'] assume_utc = cfg['cylc']['UTC mode'] cycling_mode = cfg['scheduling']['cycling mode'] # Detect (date-time) previous-format cycle point usage. has_prev_format_cycle_point = ( (initial_cycle_point is not None and PREV_DATE_TIME_REC.search(initial_cycle_point)) or (final_cycle_point is not None and PREV_DATE_TIME_REC.search(final_cycle_point))) if (has_prev_format_cycle_point and custom_dump_format != PREV_DATE_TIME_FORMAT): set_syntax_version(VERSION_PREV, "initial/final cycle point format: CCYYMMDDhh") # Detect (date-time) ISO 8601-format cycle point usage. has_new_format_cycle_point = ( (initial_cycle_point is not None and NEW_DATE_TIME_REC.search(initial_cycle_point)) or (final_cycle_point is not None and NEW_DATE_TIME_REC.search(final_cycle_point))) if has_new_format_cycle_point: set_syntax_version( VERSION_NEW, "initial/final cycle point format: non-numeric (ISO 8601?)") # Loop over all dependency sub-sections and detect cycler syntax versions. dep_sections = list(cfg['scheduling']['dependencies']) while dep_sections: dep_section = dep_sections.pop(0) if re.search("(?![^(]+\)),", dep_section): dep_sections.extend( [i.strip() for i in re.split("(?![^(]+\)),", dep_section)]) continue if dep_section == "graph": if cfg['scheduling']['dependencies']['graph']: # Using async graph in date-time cycling. set_syntax_version( VERSION_PREV, "[scheduling][[dependencies]]graph: mixed with " + "date-time cycling") custom_dump_format = PREV_DATE_TIME_FORMAT num_expanded_year_digits = 0 continue if convert_old_cycler_syntax(dep_section, only_detect_old=True): # Detected prev-format (old) syntax. set_syntax_version( VERSION_PREV, "[scheduling][[dependencies]][[[%s]]]: old-style cycling" % dep_section) custom_dump_format = PREV_DATE_TIME_FORMAT num_expanded_year_digits = 0 else: # Detected new-style syntax. set_syntax_version( VERSION_NEW, ("[scheduling][[dependencies]][[[%s]]]: " % dep_section) + "ISO 8601-style cycling") init(num_expanded_year_digits=num_expanded_year_digits, custom_dump_format=custom_dump_format, time_zone=time_zone, assume_utc=assume_utc, cycling_mode=cycling_mode)
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