Skip to content

Commit

Permalink
multiple changes:
Browse files Browse the repository at this point in the history
- implement looper mod command; closes #64
- look for ditfile in dir parents; #253
  • Loading branch information
stolarczyk committed May 5, 2020
1 parent a13b7cf commit aea82df
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 16 deletions.
13 changes: 8 additions & 5 deletions looper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ def build_parser():
"check": "Check flag status of current runs.",
"clean": "Run clean scripts of already processed jobs.",
"inspect": "Print information about a project.",
"init": "Initialize looper dotfile."}
"init": "Initialize looper dotfile.",
"mod": "Modify looper dotfile."
}

subparsers = parser.add_subparsers(dest="command")

Expand All @@ -122,8 +124,9 @@ def add_subparser(cmd):
clean_subparser = add_subparser("clean")
inspect_subparser = add_subparser("inspect")
init_subparser = add_subparser("init")
mod_subparser = add_subparser("mod")
for subparser in [run_subparser, rerun_subparser, collate_subparser,
init_subparser]:
init_subparser, mod_subparser]:
subparser.add_argument(
"--ignore-flags", dest="ignore_flags", default=False,
action=_StoreBoolActionType, type=html_checkbox(checked=False),
Expand Down Expand Up @@ -160,7 +163,7 @@ def add_subparser(cmd):
help="String to append to every command, "
"overriding values in PEP.")

for subparser in [run_subparser, rerun_subparser, init_subparser]:
for subparser in [run_subparser, rerun_subparser, init_subparser, mod_subparser]:
# Note that defaults for otherwise numeric lump parameters are set to
# null by default so that the logic that parses their values may
# distinguish between explicit 0 and lack of specification.
Expand Down Expand Up @@ -188,7 +191,7 @@ def add_subparser(cmd):
type=html_select(choices=FLAGS),
help="Check on only these flags/status values.")

for subparser in [destroy_subparser, clean_subparser, init_subparser]:
for subparser in [destroy_subparser, clean_subparser, init_subparser, mod_subparser]:
subparser.add_argument(
"--force-yes", action=_StoreBoolActionType, default=False,
type=html_checkbox(checked=False),
Expand All @@ -199,7 +202,7 @@ def add_subparser(cmd):
for subparser in [run_subparser, rerun_subparser, table_subparser,
report_subparser, destroy_subparser, check_subparser,
clean_subparser, collate_subparser, inspect_subparser,
init_subparser]:
init_subparser, mod_subparser]:
subparser.add_argument("config_file", nargs="?",
help="Project configuration file (YAML).")
subparser.add_argument(
Expand Down
8 changes: 5 additions & 3 deletions looper/looper.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,10 +702,12 @@ def main():
global _LOGGER
parser = build_parser()
args, remaining_args = parser.parse_known_args()
dotfile_path = os.path.join(os.getcwd(), LOOPER_DOTFILE_NAME)
if args.command == "init":
sys.exit(int(not init_dotfile(parser, dotfile_path, args)))
args = enrich_args_via_dotfile(args, dotfile_path)
sys.exit(int(not write_dotfile(parser, dotfile_path(), args)))
if args.command == "mod":
sys.exit(int(not write_dotfile(parser, dotfile_path(must_exist=True),
args, update=True)))
args = enrich_args_via_dotfile(args, dotfile_path())
if args.command is None:
parser.print_help(sys.stderr)
sys.exit(1)
Expand Down
46 changes: 38 additions & 8 deletions looper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,24 +296,54 @@ def enrich_args_via_dotfile(parser_args, dotfile_path):
return result


def init_dotfile(parser, path, arg_values=None):
def write_dotfile(parser, path, arg_values=None, update=False):
"""
Print out available dests and respective defaults in the provided subparser
:param argparse.ArgumentParser parser: parser to examine
:param argparse.Namespace arg_values: argument values
:param bool update: whether the file should be read, updated and written to
:return bool: whether the initialization happened successfully
"""
if os.path.exists(path):
if not update and os.path.exists(path):
print("Can't initialize, file exists: {}".format(path))
return False
arg_values = vars(arg_values) if arg_values is not None else dict()
defaults = merge_dicts(parser.arg_defaults(top_level=True),
parser.arg_defaults(unique=True))
for k, v in arg_values.items():
if k in defaults:
defaults[k] = arg_values[k]
if update:
with open(path, 'r') as dotfile:
defaults = yaml.safe_load(dotfile)
else:
defaults = merge_dicts(parser.arg_defaults(top_level=True),
parser.arg_defaults(unique=True))
defaults.update(arg_values)
with open(path, 'w') as dotfile:
yaml.dump({k: str(v) for k, v in defaults.items()}, dotfile)
print("Initialized looper dotfile in: {}".format(path))
print("{} looper dotfile: {}".
format("Modified" if update else "Initialized", path))
return True


def dotfile_path(directory=os.getcwd(), must_exist=False):
"""
Get the path to the looper dotfile
If file existence is forced this function will look for it in
the directory parents
:param str directory: directory path to start the search in
:param bool must_exist: whether the file must exist
:return str: path to the dotfile
:raise OSError: if the file does not exist
"""
cur_dir = directory
if not must_exist:
return os.path.join(cur_dir, LOOPER_DOTFILE_NAME)
while True:
parent_dir = os.path.dirname(cur_dir)
if LOOPER_DOTFILE_NAME in os.listdir(cur_dir):
return os.path.join(cur_dir, LOOPER_DOTFILE_NAME)
if cur_dir == parent_dir:
# root, file does not exist
raise OSError("Looper dotfile ({}) not found in '{}' and all "
"its parents".format(LOOPER_DOTFILE_NAME, directory))
cur_dir = parent_dir

0 comments on commit aea82df

Please sign in to comment.