From d882274ee2c523d36c230371f6858291dd02e114 Mon Sep 17 00:00:00 2001 From: Rafael Steil Date: Sun, 9 May 2021 22:09:50 -0400 Subject: [PATCH 1/6] New configuration option for interactive --- .gitignore | 1 + README.md | 19 +++++++++++++++++++ src/plotman/_tests/configuration_test.py | 15 +++++++++++++++ src/plotman/configuration.py | 9 +++++++++ src/plotman/interactive.py | 18 ++++++++++++------ src/plotman/plotman.py | 23 ++++++++++++++++++++--- src/plotman/resources/plotman.yaml | 7 +++++++ 7 files changed, 83 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 16303851..ca379a55 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__ venv .DS_Store .vscode +src/plotman.egg-info diff --git a/README.md b/README.md index b53e4244..35aacff8 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,25 @@ archive jobs initiated. This is the one part of the interactive tool which is stateful. There is no permanent record of these executed command lines, so if you start a new interactive plotman session, this log is empty. +## `plotman` commands +To get a complete list of all available commands run: +```shell +plotman -h +``` + +You can also use `plotman -h` to get help about a specific command, like +```shell +plotman interactive -h +``` + +## Running `plotman` as a daemon +> _PS: this section assumes that you have already configured `plotman.yaml`._ + +By default the command `plotman plot` will start the plotting job and continue to run on the foregroud as long as you keep the terminal window open. If you want to have it constantly running, try the following: +```shell +nohup plotman plot >> ~/plotman.log 2>&1 & +``` + ## Limitations and Issues The system is tested on Linux only. Plotman should be generalizable to other diff --git a/src/plotman/_tests/configuration_test.py b/src/plotman/_tests/configuration_test.py index f0a548b6..2e6c7c86 100644 --- a/src/plotman/_tests/configuration_test.py +++ b/src/plotman/_tests/configuration_test.py @@ -18,6 +18,21 @@ def test_get_validated_configs__default(config_text): res = configuration.get_validated_configs(config_text, '') assert isinstance(res, configuration.PlotmanConfig) +def test_tool_interactive_should_be_none(config_text): + """When tools/interacting doesn't exist, its configuration property should be None""" + loaded_yaml = yaml.load(config_text, Loader=yaml.SafeLoader) + + del loaded_yaml["tools"]["interactive"] + reloaded_yaml = configuration.get_validated_configs(yaml.dump(loaded_yaml, Dumper=yaml.SafeDumper), '') + assert reloaded_yaml.tools.interactive is None + +def test_tool_section_does_not_exist(config_text): + """When tools doesn't exist, its configuration property should be None""" + loaded_yaml = yaml.load(config_text, Loader=yaml.SafeLoader) + + del loaded_yaml["tools"] + reloaded_yaml = configuration.get_validated_configs(yaml.dump(loaded_yaml, Dumper=yaml.SafeDumper), '') + assert reloaded_yaml.tools is None def test_get_validated_configs__malformed(config_text): """Check that get_validated_configs() raises exception with invalid plotman.yaml contents.""" diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index 2434456e..3bf3378c 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -94,9 +94,18 @@ class Plotting: class UserInterface: use_stty_size: bool = True +@attr.frozen +class Interactive: + autostart_plotting: bool + +@attr.frozen +class Tools: + interactive: Optional[Interactive] = None + @attr.frozen class PlotmanConfig: directories: Directories scheduling: Scheduling plotting: Plotting + tools: Optional[Tools] = None user_interface: UserInterface = attr.ib(factory=UserInterface) diff --git a/src/plotman/interactive.py b/src/plotman/interactive.py index 5835b18d..403fb800 100644 --- a/src/plotman/interactive.py +++ b/src/plotman/interactive.py @@ -4,7 +4,7 @@ import math import os import subprocess - +import sys from plotman import archive, configuration, manager, reporting from plotman.job import Job @@ -62,14 +62,21 @@ def archiving_status_msg(configured, active, status): else: return '(not configured)' -def curses_main(stdscr): +# cmd_autostart_plotting is the (optional) argument passed from the command line. May be None +def curses_main(stdscr, cmd_autostart_plotting): log = Log() config_path = configuration.get_path() config_text = configuration.read_configuration_text(config_path) cfg = configuration.get_validated_configs(config_text, config_path) - plotting_active = True + if cmd_autostart_plotting is not None: + plotting_active = cmd_autostart_plotting + elif cfg.tools is not None and cfg.tools.interactive is not None: + plotting_active = cfg.tools.interactive.autostart_plotting + else: + plotting_active = True + archiving_configured = cfg.directories.archive is not None archiving_active = archiving_configured @@ -324,14 +331,13 @@ def curses_main(stdscr): else: pressed_key = key - -def run_interactive(): +def run_interactive(autostart_plotting = None): locale.setlocale(locale.LC_ALL, '') code = locale.getpreferredencoding() # Then use code as the encoding for str.encode() calls. try: - curses.wrapper(curses_main) + curses.wrapper(curses_main, autostart_plotting) except curses.error as e: raise TerminalTooSmallError( "Your terminal may be too small, try making it bigger.", diff --git a/src/plotman/plotman.py b/src/plotman/plotman.py index d3468735..7ffd6dee 100755 --- a/src/plotman/plotman.py +++ b/src/plotman/plotman.py @@ -5,13 +5,13 @@ import random from shutil import copyfile import time +import sys # Plotman libraries from plotman import analyzer, archive, configuration, interactive, manager, plot_util, reporting from plotman import resources as plotman_resources from plotman.job import Job - class PlotmanArgParser: def add_idprefix_arg(self, subparser): subparser.add_argument( @@ -30,7 +30,16 @@ def parse_args(self): sp.add_parser('dirs', help='show directories info') - sp.add_parser('interactive', help='run interactive control/monitoring mode') + p_interactive = sp.add_parser('interactive', help='run interactive control/monitoring mode') + p_interactive.add_argument('--autostart-plotting', + action='store_true', + default=None, + help='Automatically start plotting when the tool opens') + + p_interactive.add_argument('--no-autostart-plotting', + action='store_true', + default=None, + help='Do not start plotting when the tool opens') sp.add_parser('dsched', help='print destination dir schedule') @@ -170,7 +179,15 @@ def main(): print(reporting.dirs_report(jobs, cfg.directories, cfg.scheduling, get_term_width())) elif args.cmd == 'interactive': - interactive.run_interactive() + if args.autostart_plotting is not None: + autostart_plotting = True + elif args.no_autostart_plotting is not None: + autostart_plotting = False + else: + # In this case we'll check the configuration file + autostart_plotting = None + + interactive.run_interactive(autostart_plotting) # Start running archival elif args.cmd == 'archive': diff --git a/src/plotman/resources/plotman.yaml b/src/plotman/resources/plotman.yaml index 73269f7a..f1601616 100644 --- a/src/plotman/resources/plotman.yaml +++ b/src/plotman/resources/plotman.yaml @@ -9,6 +9,13 @@ user_interface: # you resize the terminal window, you can try setting this to True. use_stty_size: True +# Optional custom settings for the tools (status, interactive etc) +tools: + interactive: + # Set it to False if you don't want to auto start plotting when 'interactive' is ran. + # You can override this value from the command line, type "plotman interactive -h" for details + autostart_plotting: True + # Where to plot and log. directories: # One directory in which to store all plot job logs (the STDOUT/ From 900039de1686204ca0c6128caf5856f2e867ff11 Mon Sep 17 00:00:00 2001 From: Rafael Steil Date: Tue, 11 May 2021 07:18:50 -0400 Subject: [PATCH 2/6] Class defaults match config defaults Co-authored-by: Kyle Altendorf --- src/plotman/configuration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index 3bf3378c..92226039 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -96,11 +96,11 @@ class UserInterface: @attr.frozen class Interactive: - autostart_plotting: bool + autostart_plotting: bool = True @attr.frozen class Tools: - interactive: Optional[Interactive] = None + interactive: Interactive = attr.ib(factory=Interactive) @attr.frozen class PlotmanConfig: From bea021b8bad65760dc4b133509b36039d9b81c0f Mon Sep 17 00:00:00 2001 From: Rafael Steil Date: Tue, 11 May 2021 07:33:25 -0400 Subject: [PATCH 3/6] Rename Tools to Commands --- src/plotman/configuration.py | 4 ++-- src/plotman/interactive.py | 6 +++--- src/plotman/resources/plotman.yaml | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index 92226039..af4473cb 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -99,7 +99,7 @@ class Interactive: autostart_plotting: bool = True @attr.frozen -class Tools: +class Commands: interactive: Interactive = attr.ib(factory=Interactive) @attr.frozen @@ -107,5 +107,5 @@ class PlotmanConfig: directories: Directories scheduling: Scheduling plotting: Plotting - tools: Optional[Tools] = None + commands: Optional[Commands] = None user_interface: UserInterface = attr.ib(factory=UserInterface) diff --git a/src/plotman/interactive.py b/src/plotman/interactive.py index 403fb800..a8595a7d 100644 --- a/src/plotman/interactive.py +++ b/src/plotman/interactive.py @@ -72,8 +72,8 @@ def curses_main(stdscr, cmd_autostart_plotting): if cmd_autostart_plotting is not None: plotting_active = cmd_autostart_plotting - elif cfg.tools is not None and cfg.tools.interactive is not None: - plotting_active = cfg.tools.interactive.autostart_plotting + elif cfg.commands is not None: + plotting_active = cfg.commands.interactive.autostart_plotting else: plotting_active = True @@ -120,7 +120,7 @@ def curses_main(stdscr, cmd_autostart_plotting): last_refresh = datetime.datetime.now() jobs = Job.get_running_jobs(cfg.directories.log) - if plotting_active: + if False and plotting_active: (started, msg) = manager.maybe_start_new_plot( cfg.directories, cfg.scheduling, cfg.plotting ) diff --git a/src/plotman/resources/plotman.yaml b/src/plotman/resources/plotman.yaml index f1601616..4d89be5f 100644 --- a/src/plotman/resources/plotman.yaml +++ b/src/plotman/resources/plotman.yaml @@ -9,8 +9,8 @@ user_interface: # you resize the terminal window, you can try setting this to True. use_stty_size: True -# Optional custom settings for the tools (status, interactive etc) -tools: +# Optional custom settings for the subcommands (status, interactive etc) +commands: interactive: # Set it to False if you don't want to auto start plotting when 'interactive' is ran. # You can override this value from the command line, type "plotman interactive -h" for details From 954b4fb833934cb53b0b025a8cb515fe5662d6c9 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 31 May 2021 22:46:51 -0400 Subject: [PATCH 4/6] simplify --no-* option handling --- src/plotman/configuration.py | 2 +- src/plotman/interactive.py | 4 +--- src/plotman/plotman.py | 21 +++------------------ 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index af4473cb..86f61c27 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -107,5 +107,5 @@ class PlotmanConfig: directories: Directories scheduling: Scheduling plotting: Plotting - commands: Optional[Commands] = None + commands: Commands = attr.ib(factory=Commands) user_interface: UserInterface = attr.ib(factory=UserInterface) diff --git a/src/plotman/interactive.py b/src/plotman/interactive.py index a8595a7d..6787fec5 100644 --- a/src/plotman/interactive.py +++ b/src/plotman/interactive.py @@ -72,10 +72,8 @@ def curses_main(stdscr, cmd_autostart_plotting): if cmd_autostart_plotting is not None: plotting_active = cmd_autostart_plotting - elif cfg.commands is not None: - plotting_active = cfg.commands.interactive.autostart_plotting else: - plotting_active = True + plotting_active = cfg.commands.interactive.autostart_plotting archiving_configured = cfg.directories.archive is not None archiving_active = archiving_configured diff --git a/src/plotman/plotman.py b/src/plotman/plotman.py index 7ffd6dee..2ac2b8ef 100755 --- a/src/plotman/plotman.py +++ b/src/plotman/plotman.py @@ -31,15 +31,8 @@ def parse_args(self): sp.add_parser('dirs', help='show directories info') p_interactive = sp.add_parser('interactive', help='run interactive control/monitoring mode') - p_interactive.add_argument('--autostart-plotting', - action='store_true', - default=None, - help='Automatically start plotting when the tool opens') - - p_interactive.add_argument('--no-autostart-plotting', - action='store_true', - default=None, - help='Do not start plotting when the tool opens') + p_interactive.add_argument('--autostart-plotting', action='store_true', default=None, dest='autostart_plotting') + p_interactive.add_argument('--no-autostart-plotting', action='store_false', default=None, dest='autostart_plotting') sp.add_parser('dsched', help='print destination dir schedule') @@ -179,15 +172,7 @@ def main(): print(reporting.dirs_report(jobs, cfg.directories, cfg.scheduling, get_term_width())) elif args.cmd == 'interactive': - if args.autostart_plotting is not None: - autostart_plotting = True - elif args.no_autostart_plotting is not None: - autostart_plotting = False - else: - # In this case we'll check the configuration file - autostart_plotting = None - - interactive.run_interactive(autostart_plotting) + interactive.run_interactive(args.autostart_plotting) # Start running archival elif args.cmd == 'archive': From 4666b8078be824c0e4df0e6856b582b2a8303626 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 31 May 2021 23:01:05 -0400 Subject: [PATCH 5/6] cleanup --- src/plotman/interactive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plotman/interactive.py b/src/plotman/interactive.py index ed853ac1..bd5e7307 100644 --- a/src/plotman/interactive.py +++ b/src/plotman/interactive.py @@ -118,7 +118,7 @@ def curses_main(stdscr, cmd_autostart_plotting): last_refresh = datetime.datetime.now() jobs = Job.get_running_jobs(cfg.directories.log) - if False and plotting_active: + if plotting_active: (started, msg) = manager.maybe_start_new_plot( cfg.directories, cfg.scheduling, cfg.plotting ) From aca45997ab86190f33d6edf6066adb6408698713 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 31 May 2021 23:05:31 -0400 Subject: [PATCH 6/6] remove tests no longer needed due to config defaults --- src/plotman/_tests/configuration_test.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/plotman/_tests/configuration_test.py b/src/plotman/_tests/configuration_test.py index 406cad69..3424aa06 100644 --- a/src/plotman/_tests/configuration_test.py +++ b/src/plotman/_tests/configuration_test.py @@ -18,22 +18,6 @@ def test_get_validated_configs__default(config_text): res = configuration.get_validated_configs(config_text, '') assert isinstance(res, configuration.PlotmanConfig) -def test_tool_interactive_should_be_none(config_text): - """When tools/interacting doesn't exist, its configuration property should be None""" - loaded_yaml = yaml.load(config_text, Loader=yaml.SafeLoader) - - del loaded_yaml["tools"]["interactive"] - reloaded_yaml = configuration.get_validated_configs(yaml.dump(loaded_yaml, Dumper=yaml.SafeDumper), '') - assert reloaded_yaml.tools.interactive is None - -def test_tool_section_does_not_exist(config_text): - """When tools doesn't exist, its configuration property should be None""" - loaded_yaml = yaml.load(config_text, Loader=yaml.SafeLoader) - - del loaded_yaml["tools"] - reloaded_yaml = configuration.get_validated_configs(yaml.dump(loaded_yaml, Dumper=yaml.SafeDumper), '') - assert reloaded_yaml.tools is None - def test_get_validated_configs__malformed(config_text): """Check that get_validated_configs() raises exception with invalid plotman.yaml contents.""" loaded_yaml = yaml.load(config_text, Loader=yaml.SafeLoader)