Пример #1
0
    def coerce_xtrigger(self, value, keys):
        """Coerce a string into an xtrigger function context object.

        func_name(*func_args, **func_kwargs)
        Checks for legal string templates in arg values too.

        """

        label = keys[-1]
        value = self.strip_and_unquote(keys, value)
        if not value:
            raise IllegalValueError("xtrigger", keys, value)
        fname = None
        args = []
        kwargs = {}
        match = self._REC_TRIG_FUNC.match(value)
        if match is None:
            raise IllegalValueError("xtrigger", keys, value)
        fname, fargs, intvl = match.groups()
        if intvl:
            intvl = self.coerce_interval(intvl, keys)

        if fargs:
            # Extract function args and kwargs.
            for farg in fargs.split(r','):
                try:
                    key, val = farg.strip().split(r'=', 1)
                except ValueError:
                    args.append(self._coerce_type(farg.strip()))
                else:
                    kwargs[key.strip()] = self._coerce_type(val.strip())

        return SubFuncContext(label, fname, args, kwargs, intvl)
Пример #2
0
 def coerce_cycle_point_format(cls, value, keys):
     """Coerce to a cycle point format (either CCYYMM... or %Y%m...)."""
     value = cls.strip_and_unquote(keys, value)
     if not value:
         return None
     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
Пример #3
0
 def coerce_cycle_point(cls, value, keys):
     """Coerce value to a cycle point."""
     if not value:
         return None
     value = cls.strip_and_unquote(keys, value)
     if value == 'now':
         # Handle this later in config.py when the suite UTC mode is known.
         return value
     if value.isdigit():
         # 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):
             try:
                 TimePointParser(num_expanded_year_digits=i).parse(value)
             except ValueError:
                 continue
             return value
         raise IllegalValueError('cycle point', keys, value)
     try:
         TimePointParser().parse(value)
     except ValueError:
         raise IllegalValueError('cycle point', keys, value)
     return value
Пример #4
0
def _coerce_cycletime(value, keys, _):
    """Coerce value to a cycle point."""
    if not value:
        return None
    value = _strip_and_unquote(keys, value)
    if value == "now":
        # Handle this later in config.py when the suite UTC mode is known.
        return 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)
    return value
Пример #5
0
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
Пример #6
0
def coerce_xtrig(value, keys, _):
    """Coerce a string into an xtrigger function context object.

    func_name(*func_args, **func_kwargs)
    Checks for legal string templates in arg values too.

    """

    def coerce_type(in_str):
        """Convert in_str to int, float, or bool, if possible."""
        try:
            val = int(in_str)
        except ValueError:
            try:
                val = float(in_str)
            except ValueError:
                if in_str == 'False':
                    val = False
                elif in_str == 'True':
                    val = True
                else:
                    # Leave as string.
                    val = _strip_and_unquote([], in_str)
        return val

    label = keys[-1]
    value = _strip_and_unquote(keys, value)
    if not value:
        raise IllegalValueError("xtrigger", keys, value)
    fname = None
    args = []
    kwargs = {}
    m = RE_TRIG_FUNC.match(value)
    if m is None:
        raise IllegalValueError("xtrigger", keys, value)
    fname, fargs, intvl = m.groups()
    if intvl is None:
        seconds = DEFAULT_XTRIG_INTVL_SECS
    else:
        seconds = float(coerce_interval(intvl, keys, None))

    if fargs:
        # Extract function args and kwargs.
        for farg in re.split(r'\s*,\s*', fargs):
            try:
                key, val = re.split(r'\s*=\s*', farg)
            except ValueError:
                args.append(coerce_type(farg.strip()))
            else:
                kwargs[key.strip()] = coerce_type(val)

    return SuiteFuncContext(label, fname, args, kwargs, seconds)
Пример #7
0
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)
Пример #8
0
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
Пример #9
0
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
Пример #10
0
    def coerce_parameter_list(cls, value, keys):
        """Coerce parameter list.

        Args:
            value (str):
                This can be a list of str values. Each str value must conform
                to the same restriction as a task name.
                Otherwise, this can be a mixture of int ranges and int values.
            keys (list):
                Keys in nested dict that represents the raw configuration.

        Return (list):
            A list of strings or a list of sorted integers.

        Raise:
            IllegalValueError:
                If value has both str and int range or if a str value breaks
                the task name restriction.
        """
        items = []
        can_only_be = None  # A flag to prevent mixing str and int range
        for item in cls.strip_and_unquote_list(keys, value):
            values = cls.parse_int_range(item)
            if values is not None:
                if can_only_be == str:
                    raise IllegalValueError('parameter', keys, value,
                                            'mixing int range and str')
                can_only_be = int
                items.extend(values)
            elif cls._REC_NAME_SUFFIX.match(item):
                try:
                    int(item)
                except ValueError:
                    if can_only_be == int:
                        raise IllegalValueError('parameter', keys, value,
                                                'mixing int range and str')
                    can_only_be = str
                items.append(item)
            else:
                raise IllegalValueError('parameter', keys, value,
                                        '%s: bad value' % item)
        try:
            return [int(item) for item in items]
        except ValueError:
            return items
Пример #11
0
def get_interval_as_seconds(intvl, keys=None):
    """Convert an ISO 8601 interval to seconds."""
    if keys is None:
        keys = []
    try:
        interval = DURATION_PARSER.parse(intvl)
    except ValueError:
        raise IllegalValueError("ISO 8601 interval", keys, intvl)
    days, seconds = interval.get_days_and_seconds()
    return days * CALENDAR.SECONDS_IN_DAY + seconds
Пример #12
0
def _coerce_cycleinterval(value, keys, _):
    """Coerce value to a cycle interval."""
    if not value:
        return None
    value = _strip_and_unquote(keys, value)
    parser = DurationParser()
    try:
        parser.parse(value)
    except ValueError:
        raise IllegalValueError("interval", keys, value)
    return value
Пример #13
0
def _coerce_parameter_list(value, keys, _):
    """Coerce parameter list

    Can be:
    * A list of str values. Each str value must conform to the same restriction
      as a task name. Return list of str values.
    * A mixture of int ranges and int values. Return list of str values
      containing the sorted int list, zero-padded to the same width.

    Raise IllegalValueError if:
    * Mixing str and int range.
    * A str value breaks the task name restriction.
    """
    items = []
    can_only_be = None  # A flag to prevent mixing str and int range
    for item in _strip_and_unquote_list(keys, value):
        match = REC_PARAM_INT_RANGE.match(item)
        if match:
            if can_only_be == str:
                raise IllegalValueError('parameter', keys, value,
                                        'mixing int range and str')
            can_only_be = int
            lower, upper, step = match.groups()
            if not step:
                step = 1
            items.extend(range(int(lower), int(upper) + 1, int(step)))
        elif TaskID.NAME_SUFFIX_REC.match(item):
            if not item.isdigit():
                if can_only_be == int:
                    raise IllegalValueError('parameter', keys, value,
                                            'mixing int range and str')
                can_only_be = str
            items.append(item)
        else:
            raise IllegalValueError('parameter', keys, value,
                                    '%s: bad value' % item)
    if not items or can_only_be == str or any(not str(item).isdigit()
                                              for item in items):
        return items
    else:
        return [int(item) for item in items]
Пример #14
0
 def coerce_cycle_point(cls, value, keys):
     """Coerce value to a cycle point."""
     if not value:
         return None
     value = cls.strip_and_unquote(keys, value)
     if value == 'now':
         # Handle this later in config.py when the suite UTC mode is known.
         return value
     if "next" in value or "previous" in value:
         # Handle this later, as for "now".
         return value
     if value.isdigit():
         # Could be an old date-time cycle point format, or integer format.
         return value
     if "P" not in value and (
             value.startswith('-') or value.startswith('+')):
         # We don't know the value given for num expanded year digits...
         for i in range(1, 101):
             try:
                 TimePointParser(num_expanded_year_digits=i).parse(value)
             except ValueError:
                 continue
             return value
         raise IllegalValueError('cycle point', keys, value)
     if "P" in value:
         # ICP is an offset
         parser = DurationParser()
         try:
             if value.startswith("-"):
                 # parser doesn't allow negative duration with this setup?
                 parser.parse(value[1:])
             else:
                 parser.parse(value)
             return value
         except ValueError:
             raise IllegalValueError("cycle point", keys, value)
     try:
         TimePointParser().parse(value)
     except ValueError:
         raise IllegalValueError('cycle point', keys, value)
     return value
Пример #15
0
def coerce_interval(value, keys, _):
    """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:
        interval = DURATION_PARSER.parse(value)
    except ValueError:
        raise IllegalValueError("ISO 8601 interval", keys, value)
    days, seconds = interval.get_days_and_seconds()
    return DurationFloat(days * CALENDAR.SECONDS_IN_DAY + seconds)
Пример #16
0
 def coerce_interval(self, value, keys):
     """Coerce an ISO 8601 interval (or number: back-comp) into seconds."""
     value = self.strip_and_unquote(keys, value)
     if not value:
         # Allow explicit empty values.
         return None
     try:
         interval = DurationParser().parse(value)
     except ValueError:
         raise IllegalValueError("ISO 8601 interval", keys, value)
     days, seconds = interval.get_days_and_seconds()
     return DurationFloat(days * Calendar.default().SECONDS_IN_DAY +
                          seconds)
Пример #17
0
def init(num_expanded_year_digits=0,
         custom_dump_format=None,
         time_zone=None,
         assume_utc=False,
         cycling_mode=None):
    """Initialise suite-setup-specific information."""

    SuiteSpecifics.interval_parser = DurationParser()

    if cycling_mode in Calendar.default().MODES:
        Calendar.default().set_mode(cycling_mode)

    if time_zone is None:
        if assume_utc:
            time_zone = "Z"
            time_zone_hours_minutes = (0, 0)
        else:
            time_zone = get_local_time_zone_format(reduced_mode=True)
            time_zone_hours_minutes = get_local_time_zone()
    else:
        time_zone_hours_minutes = TimePointDumper().get_time_zone(time_zone)
    SuiteSpecifics.ASSUMED_TIME_ZONE = time_zone_hours_minutes
    SuiteSpecifics.NUM_EXPANDED_YEAR_DIGITS = num_expanded_year_digits
    if custom_dump_format is None:
        if num_expanded_year_digits > 0:
            SuiteSpecifics.DUMP_FORMAT = EXPANDED_DATE_TIME_FORMAT + time_zone
        else:
            SuiteSpecifics.DUMP_FORMAT = DATE_TIME_FORMAT + time_zone

    else:
        SuiteSpecifics.DUMP_FORMAT = custom_dump_format
        if u"+X" not in custom_dump_format and num_expanded_year_digits:
            raise IllegalValueError('cycle point format',
                                    ('cylc', 'cycle point format'),
                                    SuiteSpecifics.DUMP_FORMAT)
    SuiteSpecifics.point_parser = TimePointParser(
        allow_only_basic=False,
        allow_truncated=True,
        num_expanded_year_digits=SuiteSpecifics.NUM_EXPANDED_YEAR_DIGITS,
        dump_format=SuiteSpecifics.DUMP_FORMAT,
        assumed_time_zone=time_zone_hours_minutes)
    custom_point_parse_function = None
    if SuiteSpecifics.DUMP_FORMAT == PREV_DATE_TIME_FORMAT:
        custom_point_parse_function = point_parse
    SuiteSpecifics.abbrev_util = CylcTimeParser(
        None,
        None,
        num_expanded_year_digits=SuiteSpecifics.NUM_EXPANDED_YEAR_DIGITS,
        dump_format=SuiteSpecifics.DUMP_FORMAT,
        custom_point_parse_function=custom_point_parse_function,
        assumed_time_zone=SuiteSpecifics.ASSUMED_TIME_ZONE)
Пример #18
0
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
Пример #19
0
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
Пример #20
0
 def coerce_cycle_point_time_zone(cls, value, keys):
     """Coerce value to a cycle point time zone format - Z, +13, -0800..."""
     value = cls.strip_and_unquote(keys, value)
     if not value:
         return None
     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
Пример #21
0
def _coerce_parameter_list(value, keys, _):
    """Coerce parameter list."""
    value = _strip_and_unquote_list(keys, value)
    if len(value) == 1:
        # May be a range e.g. '1..5' (bounds inclusive)
        try:
            lower, upper = REC_PARAM_INT_RANGE.match(value[0]).groups()
        except AttributeError:
            if '.' in value[0]:
                # Dot is illegal in node names, probably bad range syntax.
                raise IllegalValueError("parameter", keys, value)
        else:
            n_dig = len(upper)
            return [
                str(i).zfill(n_dig) for i in range(int(lower),
                                                   int(upper) + 1)
            ]
    return value
Пример #22
0
def init(num_expanded_year_digits=0, custom_dump_format=None, time_zone=None,
         assume_utc=False, cycling_mode=None):
    """Initialise suite-setup-specific information."""
    if cycling_mode in Calendar.default().MODES:
        Calendar.default().set_mode(cycling_mode)

    if time_zone is None:
        if assume_utc:
            time_zone = "Z"
            time_zone_hours_minutes = (0, 0)
        else:
            time_zone = get_local_time_zone_format(TimeZoneFormatMode.reduced)
            time_zone_hours_minutes = get_local_time_zone()
    else:
        time_zone_hours_minutes = TimePointDumper().get_time_zone(time_zone)
    SuiteSpecifics.ASSUMED_TIME_ZONE = time_zone_hours_minutes
    SuiteSpecifics.NUM_EXPANDED_YEAR_DIGITS = num_expanded_year_digits
    if custom_dump_format is None:
        if num_expanded_year_digits > 0:
            SuiteSpecifics.DUMP_FORMAT = EXPANDED_DATE_TIME_FORMAT + time_zone
        else:
            SuiteSpecifics.DUMP_FORMAT = DATE_TIME_FORMAT + time_zone
    else:
        SuiteSpecifics.DUMP_FORMAT = custom_dump_format
        if u"+X" not in custom_dump_format and num_expanded_year_digits:
            raise IllegalValueError(
                'cycle point format',
                ('cylc', 'cycle point format'),
                SuiteSpecifics.DUMP_FORMAT
            )

    SuiteSpecifics.iso8601_parsers = CylcTimeParser.initiate_parsers(
        dump_format=SuiteSpecifics.DUMP_FORMAT,
        num_expanded_year_digits=num_expanded_year_digits,
        assumed_time_zone=SuiteSpecifics.ASSUMED_TIME_ZONE
    )

    (SuiteSpecifics.point_parser,
     SuiteSpecifics.interval_parser,
     SuiteSpecifics.recurrence_parser) = SuiteSpecifics.iso8601_parsers

    SuiteSpecifics.abbrev_util = CylcTimeParser(
        None, None, SuiteSpecifics.iso8601_parsers
    )