def cli(prefix: str, path: PurePath, spec: Path, flags: List[str], logger: UI, description: str, transaction: Transaction, *args, **kwargs): # spec: Path with spec.open() as f: obj = json.load(f, object_pairs_hook=lambda pairs: pairs) try: try: array = [SpecObj(**dict(obj))] except TypeError: array = [SpecObj(**dict(o)) for o in obj] except TypeError: logger.exit(f'Each object in {spec} must have a ' f'"command" field and a "flags" field.') for i, obj in enumerate(array): new_path = path if len(array) == 1 else PurePath(path, str(i)) def parse_flag(flag: Flag): values = flag.values if isinstance(flag.values, list) else [flag.values] null_keys = ['null', '', 'none', 'None'] return [ f'--{v}' if flag.key in null_keys else f'--{flag.key}="{v}"' for v in values ] flags = [[f] for f in flags] flags += list(map(parse_flag, obj.flags)) new(path=new_path, prefix=prefix, command=obj.command, description=description, flags=flags, transaction=transaction)
def cli(prefix: str, paths: List[PurePath], commands: List[str], args: List[str], logger: UI, descriptions: List[str], transaction: Transaction, *_, **__): n = len(commands) if not len(paths) in [1, n]: logger.exit("There must either be 1 or n paths " "where n is the number of subcommands.") if not (descriptions is None or len(descriptions) in [0, 1, n]): logger.exit("There must either be 1 or n descriptions " "where n is the number of subcommands.") descriptions = descriptions or [] iterator = enumerate(itertools.zip_longest(paths, commands, descriptions)) for i, (path, command, description) in iterator: if path is None: if n == 1: path = PurePath(paths[0]) else: path = PurePath(paths[0], str(i)) if description is None: if descriptions: description = descriptions[0] new( command=Command(prefix, command, *args, path=path), description=description, path=path, transaction=transaction, )
def cli(prefix: str, paths: List[PurePath], commands: List[str], flags: List[str], logger: UI, descriptions: List[str], transaction: Transaction, *args, **kwargs): flags = list(map(parse_flag, flags)) n = len(commands) if not len(paths) in [1, n]: logger.exit('There must either be 1 or n paths ' 'where n is the number of commands.') if not len(descriptions) in [0, 1, n]: logger.exit('There must either be 1 or n descriptions ' 'where n is the number of commands.') iterator = enumerate(itertools.zip_longest(paths, commands, descriptions)) for i, (path, command, description) in iterator: if path is None: if n == 1: path = PurePath(paths[0]) else: path = PurePath(paths[0], str(i)) if len(descriptions) == 0: description = 'Description not given.' if len(descriptions) == 1: description = descriptions[0] new(path=path, prefix=prefix, command=command, description=description, flags=flags, transaction=transaction)
def cli(prefix: str, paths: List[PurePath], commands: List[str], flags: List[str], logger: UI, descriptions: List[str], transaction: Transaction, *args, **kwargs): paths = [p for p in paths if p] commands = [c for c in commands if c] if len(paths) == 0: logger.exit('Must provide at least one path.') if len(commands) == 0: logger.exit('Must provide at least one command.') if descriptions is None: descriptions = [''] * len(commands) elif len(descriptions) == 1: descriptions *= len(paths) if not len(paths) == len(commands): logger.exit('Number of paths must be the same as the number of commands') elif not len(paths) == len(commands) == len(descriptions): logger.exit( f'Got {len(paths)} paths, {len(commands)} commands, and {len(descriptions)} descriptions.' f'These numbers should all be the same so that they can be collated.') runs = defaultdict(list) for path, command, description in zip(paths, commands, descriptions): for parsed_flags in generate_runs(flags): runs[path].append((command, parsed_flags, description)) for path in runs: for i, (command, flags, description) in enumerate(runs[path]): new_path = path if len(runs[path]) > 1: new_path = PurePath(path, str(i)) new(path=new_path, prefix=prefix, command=command, description=description, flags=flags, transaction=transaction)
def cli( prefix: str, path: PurePath, spec: Path, args: List[str], logger: UI, description: str, transaction: Transaction, max_runs: int, *_, **__, ): # spec: Path if not spec.exists(): logger.exit(f"{spec.absolute()} does not exist.") with spec.open() as f: obj = json.load(f, object_pairs_hook=lambda pairs: pairs) try: try: spec_objs = [SpecObj(**dict(obj))] except ValueError: spec_objs = [SpecObj(**dict(o)) for o in obj] except TypeError: logger.exit(f"Each object in {spec} must have a " '"command" field and a "args" field.') def listify(x): if isinstance(x, list): return x return [x] def prepend(arg: str): if not arg or arg.startswith("-"): return arg return f"--{arg}" def arg_alternatives(key, values): for v in listify(values): if isinstance(v, list): value = " ".join([f'"{_v}"' for _v in v]) yield [prepend(f"{key} {value}")] else: yield [prepend(f'{key}="{value}"') for value in listify(v)] def flag_alternatives(values): if values: for v in values: yield list(map(prepend, v)) else: yield [None] def group_args(spec): for k, v in spec.args or []: yield list(arg_alternatives(k, v)) yield list(flag_alternatives(spec.flags)) def arg_assignments(): for spec in spec_objs: for arg_set in itertools.product(*group_args(spec)): yield spec.command, [a for s in arg_set for a in s if a] assignments = list(arg_assignments()) if max_runs is not None and len(assignments) > max_runs: random.shuffle(assignments) assignments = assignments[:max_runs] for i, (command, arg_set) in enumerate(assignments): new_path = path if len(assignments) == 1 else PurePath(path, str(i)) command = Command(prefix, command, *arg_set, *args, path=new_path) new( path=new_path, command=command, description=description, transaction=transaction, )