示例#1
0
 def __init__(self, fromtuple=None, **kwargs):
     super().__init__(**kwargs)
     self._fromtuple = fromtuple
     if fromtuple:
         for value in fromtuple[0]:
             self.append(value)
         for key, value in fromtuple[1].items():
             if is_container(value):
                 start = len(self)
                 for subvalue in value:
                     self.append(subvalue)
                 self.set_name(key, start, len(self))
             else:
                 self.append(value)
                 self.add_name(key)
示例#2
0
文件: snakemake.py 项目: epruesse/ymp
 def __init__(self, fromtuple=None, **kwargs):
     """"""  # blank out docstring in super class w different formatting
     super().__init__(**kwargs)
     self._fromtuple = fromtuple
     if fromtuple:
         for value in fromtuple[0]:
             self.append(value)
         for key, value in fromtuple[1].items():
             if is_container(value):
                 start = len(self)
                 for subvalue in value:
                     self.append(subvalue)
                 self._set_name(key, start, len(self))
             else:
                 self.append(value)
                 self._add_name(key)
示例#3
0
 def update_tuple(self, totuple):
     """Update values in `(args, kwargs)` tuple.
     The tuple must be the same as used in the constructor and
     must not have been modified.
     """
     args, kwargs = totuple
     for n, value in enumerate(args):
         if args[n] != self[n]:
             args[n] = self[n]
     for key, value in kwargs.items():
         start, end = self._names[key]
         if end:
             assert is_container(value)
             for k, j in enumerate(range(start, end)):
                 if kwargs[key][k] != self[j]:
                     kwargs[key][k] = self[j]
         else:
             if kwargs[key] != self[start]:
                 kwargs[key] = self[start]
示例#4
0
文件: snakemake.py 项目: epruesse/ymp
    def expand(self, rule, ruleinfo):
        """Recursively expand wildcards within :class:`RuleInfo` object"""
        fields = list(
            filter(lambda x: x is not None,
                   filter(self.expands_field, ruleinfo_fields)))
        # normalize field values and create namedlist dictionary
        args = {}
        for field in fields:
            attr = getattr(ruleinfo, field)
            if isinstance(attr, tuple):
                if len(attr) != 2:
                    raise Exception("Internal Error")
                # flatten named lists
                for key in attr[1]:
                    if is_container(attr[1][key]):
                        attr[1][key] = list(flatten(attr[1][key]))
                # flatten unnamed and overwrite tuples
                # also turn attr[0] into a list, making it mutable
                attr = (list(flatten(attr[0])), attr[1])

                setattr(ruleinfo, field, attr)
                args[field] = NamedList(fromtuple=attr)
            else:
                args[field] = NamedList()
                args[field].append(attr)

        # build graph of expansion dependencies
        deps = networkx().DiGraph()
        for field, nlist in args.items():
            for n, value in enumerate(nlist):
                if not isinstance(value, str):  # only strings can be expanded
                    continue
                s = "{}[{}]".format(field, n)
                # create node for value itself
                deps.add_node(s, core=True, name=field, idx=n)
                # node depends on wildcards contained in value
                deps.add_edges_from((s, t) for t in get_names(value)
                                    if t.split(".")[0].split("[")[0] in fields)
                # field node depends on all it's value nodes
                deps.add_edge(field, s)
            # create edges field.name -> field[n]
            for name, (i, j) in nlist.get_names():
                s = "{}.{}".format(field, name)
                if j is None:
                    j = i + 1
                deps.add_edges_from(
                    (s, "{}[{}]".format(field, n)) for n in range(i, j))

        # sort variables so that they can be expanded in order
        try:
            nodes = list(
                reversed([
                    node for node in
                    networkx().algorithms.dag.topological_sort(deps)
                    if deps.out_degree(node) > 0 and 'core' in deps.nodes[node]
                ]))
        except networkx().NetworkXUnfeasible:
            raise CircularReferenceException(deps, rule) from None

        # expand variables
        for node in nodes:
            var_name = deps.nodes[node]['name']
            var_idx = deps.nodes[node]['idx']
            value = args[var_name][var_idx]
            if not isinstance(value, str):
                continue

            # format what we can
            valnew = partial_format(value, **args)

            # check if any remaining wilcards refer to rule fields
            names = [
                re.split(r'\.|\[', name, maxsplit=1)[0]
                for name in get_names(valnew)
            ]
            field_names = ruleinfo_fields[var_name].get('funcparams', [])
            parm_names = [name for name in field_names if name in names]

            if parm_names:
                # Snakemake won't expand wildcards in output of functions,
                # so we need to format everything here
                def late_recursion(val, fparms):
                    def wrapper(wildcards, **kwargs):
                        # no partial here, fail if anything left
                        return strip_wildcard_constraints(val).format(
                            **kwargs, **wildcards)

                    # adjust the signature so that snakemake will pass us
                    # everything we need
                    parms = (Parameter(pname, Parameter.POSITIONAL_OR_KEYWORD)
                             for pname in fparms)
                    newsig = signature(wrapper).replace(parameters=parms)
                    wrapper.__signature__ = newsig
                    return wrapper

                valnew = late_recursion(valnew, parm_names)

            args[var_name][var_idx] = valnew

            if ymp.print_rule == 1:
                log.debug("{}::{}: {} => {}".format(rule.name, node, value,
                                                    valnew))

        # update ruleinfo
        for name in fields:
            attr = getattr(ruleinfo, name)
            if isinstance(attr, tuple):
                if len(attr) != 2:
                    raise Exception("Internal Error")
                args[name].update_tuple(attr)
            else:
                setattr(ruleinfo, name, args[name][0])
示例#5
0
    def expand(self, rule, ruleinfo):
        """Recursively expand wildcards within RuleInfo object"""
        fields = list(
            filter(None.__ne__, filter(self.expands_field, ruleinfo_fields)))
        # normalize field values and create namedlist dictionary
        args = {}
        for field in fields:
            attr = getattr(ruleinfo, field)
            if isinstance(attr, tuple):
                if len(attr) != 2:
                    raise Exception("Internal Error")
                # flatten named lists
                for key in attr[1]:
                    if is_container(attr[1][key]):
                        attr[1][key] = list(flatten(attr[1][key]))
                # flatten unnamed and overwrite tuples
                # also turn attr[0] into a list, making it mutable
                attr = (list(flatten(attr[0])), attr[1])

                setattr(ruleinfo, field, attr)
                args[field] = NamedList(fromtuple=attr)
            else:
                args[field] = NamedList()
                args[field].append(attr)

        # build graph of expansion dependencies
        deps = networkx().DiGraph()
        for field, nlist in args.items():
            for n, value in enumerate(nlist):
                if not isinstance(value, str):  # only strings can be expanded
                    continue
                s = "{}[{}]".format(field, n)
                # create node for value itself
                deps.add_node(s, core=True, name=field, idx=n)
                # node depends on wildcards contained in value
                deps.add_edges_from((s, t) for t in get_names(value)
                                    if t.split(".")[0].split("[")[0] in fields)
                # field node depends on all it's value nodes
                deps.add_edge(field, s)
            # create edges field.name -> field[n]
            for name, (i, j) in nlist.get_names():
                s = "{}.{}".format(field, name)
                if j is None:
                    j = i + 1
                deps.add_edges_from(
                    (s, "{}[{}]".format(field, n)) for n in range(i, j))

        # sort variables so that they can be expanded in order
        try:
            nodes = list(
                reversed([
                    node for node in
                    networkx().algorithms.dag.topological_sort(deps)
                    if deps.out_degree(node) > 0 and 'core' in deps.nodes[node]
                ]))
        except networkx().NetworkXUnfeasible:
            raise CircularReferenceException(deps, rule)

        # expand variables
        for node in nodes:
            name = deps.nodes[node]['name']
            idx = deps.nodes[node]['idx']
            value = args[name][idx]
            if isinstance(value, str):
                try:
                    value2 = partial_format(value, **args)
                except FormattingError as e:
                    raise RuleException(
                        "Unable to resolve wildcard '{{{}}}' in parameter {}"
                        "in rule {}".format(e.attr, node, rule.name))
                except IndexError as e:
                    raise RuleException(
                        "Unable to format '{}' using '{}'".format(value, args))
                args[name][idx] = value2
                if ymp.print_rule == 1:
                    log.error("{}::{}: {} => {}".format(
                        rule.name, node, value, value2))

        # update ruleinfo
        for name in fields:
            attr = getattr(ruleinfo, name)
            if isinstance(attr, tuple):
                if len(attr) != 2:
                    raise Exception("Internal Error")
                args[name].update_tuple(attr)
            else:
                setattr(ruleinfo, name, args[name][0])