diff --git a/bin/cylc-stop b/bin/cylc-stop index c815dbb97b3..b02e99a4ec9 100755 --- a/bin/cylc-stop +++ b/bin/cylc-stop @@ -51,10 +51,10 @@ from cylc.task_id import TaskID from cylc.network.suite_command import SuiteCommandClient from cylc.network.suite_info import SuiteInfoClient from cylc.option_parsers import CylcOptionParser as COP -from cylc.command_polling import poller +from cylc.command_polling import Poller -class stop_poller(poller): +class StopPoller(Poller): """A polling object that checks if a suite has stopped yet.""" def load(self): @@ -102,7 +102,7 @@ def main(): help="Shut down after time STOP (ISO 8601 formatted)", action="store", dest="wall_clock") - stop_poller.add_to_cmd_options(parser, d_max_polls=0) + StopPoller.add_to_cmd_options(parser, d_max_polls=0) (options, args) = parser.parse_args() suite = args[0] @@ -123,7 +123,7 @@ def main(): if int(options.max_polls) > 0: # (test to avoid the "nothing to do" warning for # --max-polls=0) - spoller = stop_poller( + spoller = StopPoller( "suite stopped", options.interval, options.max_polls, args={ 'suite': suite, diff --git a/bin/cylc-suite-state b/bin/cylc-suite-state index 6fe78ffde1d..2b70f6c2554 100755 --- a/bin/cylc-suite-state +++ b/bin/cylc-suite-state @@ -61,13 +61,13 @@ from cylc.option_parsers import CylcOptionParser as COP from cylc.dbstatecheck import ( CylcSuiteDBChecker, DBNotFoundError, DBOperationError) from cylc.cfgspec.globalcfg import GLOBAL_CFG -from cylc.command_polling import poller +from cylc.command_polling import Poller from cylc.task_state import TASK_STATUSES_ORDERED from isodatetime.parsers import TimePointParser, DurationParser -class suite_poller(poller): +class SuitePoller(Poller): """A polling object that checks suite state.""" def connect(self): @@ -174,7 +174,7 @@ def main(): "check for. " + conds + states, action="store", dest="status", default=None) - suite_poller.add_to_cmd_options(parser) + SuitePoller.add_to_cmd_options(parser) (options, args) = parser.parse_args(remove_opts=["--db", "--debug"]) suite = args[0] @@ -232,7 +232,7 @@ def main(): os.path.expanduser( options.run_dir or GLOBAL_CFG.get_host_item('run directory'))) - spoller = suite_poller( + spoller = SuitePoller( "requested state", options.interval, options.max_polls, args={'suite': suite, diff --git a/lib/cylc/command_polling.py b/lib/cylc/command_polling.py index 1e312b75ee7..905df7b5354 100644 --- a/lib/cylc/command_polling.py +++ b/lib/cylc/command_polling.py @@ -15,20 +15,19 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +"""Encapsulates polling activity for CLI commands.""" import sys -from time import sleep, time +from time import sleep -from cylc.suite_logging import OUT, ERR - -class poller(object): +class Poller(object): """Encapsulates polling activity for cylc commands. Derived classes must override the check() method to test the polling condition.""" @classmethod def add_to_cmd_options(cls, parser, d_interval=60, d_max_polls=10): - # add command line options for polling + """Add command line options for commands that can do polling""" parser.add_option( "--max-polls", help="Maximum number of polls (default " + str(d_max_polls) + ").", @@ -47,27 +46,29 @@ def add_to_cmd_options(cls, parser, d_interval=60, d_max_polls=10): dest="interval", default=d_interval) - def __init__(self, condition, interval, max_polls, args={}): + def __init__(self, condition, interval, max_polls, args): self.condition = condition # e.g. "suite stopped" - """check max_polls is an int""" + # check max_polls is an int try: self.max_polls = int(max_polls) - except: - ERR.error("max_polls must be an int") - sys.exit(1) + except ValueError: + sys.exit("max_polls must be an int") - """check interval is an int""" + # check interval is an int try: self.interval = int(interval) - except: - ERR.error("interval must be an integer") - sys.exit(1) + except ValueError: + sys.exit("interval must be an integer") self.n_polls = 0 self.args = args # any extra parameters needed by check() + def check(self): + """Abstract method. Test polling condition.""" + raise NotImplementedError() + def poll(self): """Poll for the condition embodied by self.check(). Return True if condition met, or False if polling exhausted.""" @@ -76,27 +77,23 @@ def poll(self): # exit 1 as we can't know if the condition is satisfied sys.exit("WARNING: nothing to do (--max-polls=0)") elif self.max_polls == 1: - log_msg = "checking" + sys.stdout.write("checking for '%s'" % self.condition) else: - log_msg = "polling" - log_msg += " for '" + self.condition + "'" + sys.stdout.write("polling for '%s'" % self.condition) - done = False - while (not done and self.n_polls < self.max_polls): + while self.n_polls < self.max_polls: self.n_polls += 1 if self.check(): - done = True - else: - if self.max_polls > 1: - log_msg += '.' - sleep(self.interval) - if done: - OUT.info(log_msg + ": satisfied") - return True - else: - OUT.info(log_msg) - err_msg = "condition not satisfied", + sys.stdout.write(": satisfied\n") + return True if self.max_polls > 1: - err_msg += "\nafter " + str(self.max_polls) + " polls" - ERR.error(err_msg) - return False + sys.stdout.write(".") + sleep(self.interval) + sys.stdout.write("\n") + if self.max_polls > 1: + sys.stderr.write( + "ERROR: condition not satisfied after %d polls\n" % + self.max_polls) + else: + sys.stderr.write("ERROR: condition not satisfied\n") + return False