def replace_prefix(self, path, property=None): if (self.trie is None and self.prefix is None) or ( property in self.skip_properties or os.path.isabs(path) or path.startswith("..") or is_flagged(path, "remote_object") or is_callable(path)): # no replacement return path if self.trie is not None: prefixes = self.trie.prefix_items(str(path)) if len(prefixes) > 1: # ambiguous prefixes raise WorkflowError( "Multiple prefixes ({}) match the path {}. Make sure that the replace_prefix statement " "in your module definition does not yield ambiguous matches." .format(", ".join(prefix[0] for prefix in prefixes), path)) elif prefixes: # replace prefix prefix, replacement = prefixes[0] return replacement + path[len(prefix):] else: # no matching prefix return path else: # prefix case return self.prefix + path
def modify_callable(item): if is_callable(item): # For callables ensure that the rule's original path modifier is applied as well. def inner(wildcards): return self.rule.apply_path_modifier( item(wildcards), self.rule.input_modifier, property="input") return inner else: # For strings, the path modifier has been already applied. return item
def expand_report_argument(item, wildcards, job): if is_callable(item): aux_params = get_input_function_aux_params(item, {"params": job.params}) try: item = item(wildcards, **aux_params) except Exception as e: raise InputFunctionException(e, rule=job.rule, wildcards=wildcards) if isinstance(item, str): try: return apply_wildcards(item, wildcards) except AttributeError as e: raise WorkflowError("Failed to resolve wildcards.", e, rule=job.rule) else: return item
def _apply_wildcards( self, newitems, olditems, wildcards, concretize=None, check_return_type=True, omit_callable=False, mapping=None, no_flattening=False, aux_params=None, apply_path_modifier=True, property=None, incomplete_checkpoint_func=lambda e: None, allow_unpack=True, ): if aux_params is None: aux_params = dict() for name, item in olditems._allitems(): start = len(newitems) is_unpack = is_flagged(item, "unpack") _is_callable = is_callable(item) if _is_callable: if omit_callable: continue item, incomplete = self.apply_input_function( item, wildcards, incomplete_checkpoint_func=incomplete_checkpoint_func, is_unpack=is_unpack, **aux_params) if apply_path_modifier: item = self.apply_path_modifier(item, property=property) if is_unpack and not incomplete: if not allow_unpack: raise WorkflowError( "unpack() is not allowed with params. " "Simply return a dictionary which can be directly ." "used, e.g. via {params[mykey]}.") # Sanity checks before interpreting unpack() if not isinstance(item, (list, dict)): raise WorkflowError( "Can only use unpack() on list and dict", rule=self) if name: raise WorkflowError( "Cannot combine named input file with unpack()", rule=self) # Allow streamlined code with/without unpack if isinstance(item, list): pairs = zip([None] * len(item), item) else: assert isinstance(item, dict) pairs = item.items() else: pairs = [(name, item)] for name, item in pairs: is_iterable = True if not_iterable(item) or no_flattening: item = [item] is_iterable = False for item_ in item: if (check_return_type and not isinstance(item_, str) and not isinstance(item_, Path)): raise WorkflowError( "Function did not return str or list " "of str.", rule=self) concrete = concretize(item_, wildcards, _is_callable) newitems.append(concrete) if mapping is not None: mapping[concrete] = item_ if name: newitems._set_name( name, start, end=len(newitems) if is_iterable else None) start = len(newitems)
def _apply_wildcards(self, newitems, olditems, wildcards, concretize=apply_wildcards, check_return_type=True, omit_callable=False, mapping=None, no_flattening=False, aux_params=None, apply_default_remote=True): if aux_params is None: aux_params = dict() for name, item in olditems.allitems(): start = len(newitems) is_iterable = True is_unpack = is_flagged(item, "unpack") if is_callable(item): if omit_callable: continue item = self.apply_input_function(item, wildcards, **aux_params) if apply_default_remote: item = self.apply_default_remote(item) if is_unpack: # Sanity checks before interpreting unpack() if not isinstance(item, (list, dict)): raise WorkflowError( "Can only use unpack() on list and dict", rule=self) if name: raise WorkflowError( "Cannot combine named input file with unpack()", rule=self) # Allow streamlined code with/without unpack if isinstance(item, list): pairs = zip([None] * len(item), item) else: assert isinstance(item, dict) pairs = item.items() else: pairs = [(name, item)] for name, item in pairs: if not_iterable(item) or no_flattening: item = [item] is_iterable = False for item_ in item: if check_return_type and not isinstance(item_, str): raise WorkflowError( "Function did not return str or list " "of str.", rule=self) concrete = concretize(item_, wildcards) newitems.append(concrete) if mapping is not None: mapping[concrete] = item_ if name: newitems.set_name( name, start, end=len(newitems) if is_iterable else None) start = len(newitems)
def render_iofile(iofile): if is_callable(iofile): return "<function>" else: return str(iofile)