Source code for kodiak.args_parser

import re
import itertools

DEFAULT_PATTERN = '\\{(.*?)\\}'


def _expand_range(nrange):
    """ Ranges are inclusive

    Without end is taken as a reverse range, ie.   '6:' is '6:0' infinite
    couldn't be as impossible so we think is an inverse range
    """
    bounds = nrange.split(":")
    if len(bounds) not in [2, 3]:
        raise ValueError("range must be of type begin:end or begin:end:step")

    start = bounds[0]
    end = bounds[1]

    if len(bounds) == 2:
        step = 1
    elif bounds[2] != '':
        step = bounds[2]
    else:
        # This branch cover the case "10::" and defaults to "10:0:1"
        step = 1

    if not start:
        start = "0"
    if not end:
        # As an infinite range is impossible we presuppose that's a reverse range
        end = "0"

    if not start.isdigit():
        raise ValueError("for ranges start must be a positive integer, but is: %s" % start)

    if not end.isdigit():
        raise ValueError("for ranges end must be a positive integers, but is: %s" % end)

    if int(start) > int(end):
        start, end = end, start
        expanded_range = reversed(range(int(start), int(end) + 1, int(step)))
    else:
        expanded_range = range(int(start), int(end) + 1, int(step))

    return [Match(e) for e in expanded_range]


[docs]class Match(object): """An object generated after the process of matching and passed to the `colbuilder` Attributes: original (str): the unmodified matched string value (str): a possible derived string from original label (str): used as the name or title of the `Match` payload (dict): a dict with extra information as `default_colbuilder` that can be used by the `colbuilder` in `kodiak_dataframe.gencol` """ def __init__(self, original, label=None, value=None, payload=None): self.original = original self.value = value if value else original self.label = label self.payload = payload if payload else {} def __eq__(self, other): if isinstance(other, self.__class__): return self.original == other.original and \ self.value == other.value and \ self.label == other.label and \ self.payload == other.payload else: return False def __ne__(self, other): return not self == other def __repr__(self): return "Match(original=%r, label=%r, value=%r, payload=%r)" % ( self.original, self.label, self.value, self.payload)
[docs]class ArgsParser(object): def __init__(self, pattern=None, separator=','): if pattern is None: pattern = DEFAULT_PATTERN self.pattern = re.compile(pattern) self.separator = separator
[docs] def parse(self, string): args = self.pattern.findall(string) template = self.pattern.sub("{}", string) group_args = [self._parse(arg) for arg in args] if len(group_args) == 0: group_args = [[Match(None)]] return template, group_args
def _parse(self, string): """ parses a whole group like '1,2:4' """ args = string.split(self.separator) def maybe_expand(arg): # return _expand_range(arg) if ':' in arg else [Match(arg)] if '=' in arg: k, v = arg.split('=', 1) return [Match(original=arg, label=k, value=v)] elif ':' in arg: return _expand_range(arg) else: return [Match(arg)] args = [maybe_expand(a) for a in args] args = list(itertools.chain.from_iterable(args)) return args