def parse(cls, line, lineno, log, cmddict): """Parses the sequence command from a line of text, according to the given command dictionary, and returns a new SeqCmd. """ delay = SeqDelay.parse(line, lineno, log, cmddict) attrs = SeqCmdAttrs.parse(line, lineno, log, cmddict) comment = SeqComment.parse(line, lineno, log, cmddict) stop = len(line) if comment: stop = comment.pos.col.start - 1 if attrs and attrs.pos.col.stop != -1: stop = attrs.pos.col.start - 1 tokens = line[:stop].split() name = tokens[1] args = tokens[2:] start = line.find(name) pos = SeqPos(line, lineno, start + 1, stop) if name not in cmddict: log.error('Unrecognized command "%s".' % name, pos) elif cmddict[name].nargs != len(args): msg = "Command argument size mismatch: expected %d, but encountered %d." log.error(msg % (cmddict[name].nargs, len(args)), pos) args = [util.toNumber(a, a) for a in args] cmd = cmddict.create(name, *args) return cls(cmd, delay, attrs, comment, pos)
def main(): log.begin() parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) # Add required command line argument parser.add_argument('filename', default=None) # Add optional command line arguments parser.add_argument('--port', default=ait.config.get('command.port', ait.DEFAULT_CMD_PORT), type=int) parser.add_argument('--verbose', default=0, type=int) # Get command line arguments args = vars(parser.parse_args()) host = '127.0.0.1' port = args['port'] data = ' '.join(args) verbose = args['verbose'] cmd = api.CmdAPI(port, verbose=verbose) filename = args['filename'] try: with open(filename, 'r') as stream: for line in stream.readlines(): line = line.strip() # Skip blank lines and comments if len(line) == 0 or line.startswith('#'): continue # Meta-command elif line.startswith('%'): command = line[1:].strip() system(command) # Sequence command else: tokens = line.split() delay = float(tokens[0]) name = tokens[1] args = [util.toNumber(t, t) for t in tokens[2:]] args = cmd.parseArgs(name, *args) time.sleep(delay) log.info(line) cmd.send(name, *args) except IOError: log.error("Could not open '%s' for reading." % filename) log.end()
def _parse_header(self, line, lineno, log): """Parses a sequence header line containing 'name: value' pairs.""" if line.startswith("#") and line.find(":") > 0: tokens = [t.strip().lower() for t in line[1:].split(":", 1)] name = tokens[0] pos = SeqPos(line, lineno) if name in self.header: msg = "Ignoring duplicate header parameter: %s" log.warning(msg % name, pos) else: for expected in ["seqid", "version"]: if name == expected: value = util.toNumber(tokens[1], None) if value is None: msg = 'Parameter "%s" value "%s" is not a number.' log.error(msg % (name, tokens[1]), pos) else: self.header[name] = value
def create(self, name, *args, **kwargs): """Creates a new AIT command with the given arguments.""" tokens = name.split() if len(tokens) > 1 and (len(args) > 0 or len(kwargs) > 0): msg = "A Cmd may be created with either positional arguments " msg += "(passed as a string or a Python list) or keyword " msg += "arguments, but not both." raise TypeError(msg) if len(tokens) > 1: name = tokens[0] args = [util.toNumber(t, t) for t in tokens[1:]] defn = self.get(name, None) if defn is None: raise TypeError("Unrecognized command: %s" % name) return createCmd(defn, *args, **kwargs) # noqa
def parseArgs(argv, defaults): """parseArgs(argv, defaults) -> (dict, list) Parses command-line arguments according to the given defaults. For every key in defaults, an argument of the form --key=value will be parsed. Numeric arguments are converted from strings with errors reported via ait.core.log.error() and default values used instead. Returns a copy of defaults with parsed option values and a list of any non-flag arguments. """ options = dict(defaults) numeric = \ [ k for k, v in options.items() if type(v) is float or type(v) is int ] try: longopts = ["%s=" % key for key in options.keys()] opts, args = getopt.getopt(argv, "", longopts) for key, value in opts: if key.startswith("--"): key = key[2:] options[key] = value except getopt.GetoptError as err: log.error(str(err)) usage(exit=True) for key in numeric: value = options[key] if type(value) is str: options[key] = util.toNumber(value) if options[key] is None: msg = "Option '%s': '%s' is not a number, using default '%s' instead." log.error(msg, key, value, defaults[key]) options[key] = defaults[key] return options, args
def main(): log.begin() descr = ( "Sends the given relative timed sequence via the AIT server, or if the 'udp' " "flag is set then directly via UDP.") parser = argparse.ArgumentParser( description=descr, formatter_class=argparse.RawDescriptionHelpFormatter) # The optional argument(s) arg_defns = OrderedDict({ "--topic": { "type": str, "default": ait.config.get("command.topic", ait.DEFAULT_CMD_TOPIC), "help": "Name of topic from which to publish data", }, "--verbose": { "action": "store_true", "default": False, "help": "Hexdump of the raw command being sent.", }, "--udp": { "action": "store_true", "default": False, "help": "Send data to UDP socket.", }, "--host": { "type": str, "default": ait.DEFAULT_CMD_HOST, "help": "Host to which to send data", }, "--port": { "type": int, "default": ait.config.get("command.port", ait.DEFAULT_CMD_PORT), "help": "Port on which to send data", }, }) # Required argument(s) arg_defns["filename"] = { "type": str, "help": "Name of the sequence file.", "default": None, } # Push argument defs to the parser for name, params in arg_defns.items(): parser.add_argument(name, **params) # Get arg results of the parser args = parser.parse_args() # Extract args to local fields host = args.host port = args.port verbose = args.verbose udp = args.udp topic = args.topic filename = args.filename # If UDP enabled, collect host/port info if udp: if host is not None: dest = (host, port) else: dest = port cmd_api = api.CmdAPI(udp_dest=dest, verbose=verbose) # Default CmdAPI connect hooks up to C&DH server 0MQ port else: cmd_api = api.CmdAPI(verbose=verbose, cmdtopic=topic) try: with open(filename, "r") as stream: for line in stream.readlines(): line = line.strip() # Skip blank lines and comments if len(line) == 0 or line.startswith("#"): continue # Meta-command elif line.startswith("%"): command = line[1:].strip() system(command) # Sequence command else: tokens = line.split() delay = float(tokens[0]) cmd_name = tokens[1] cmd_args = [util.toNumber(t, t) for t in tokens[2:]] cmd_args = cmd_api.parse_args(cmd_name, *cmd_args) time.sleep(delay) log.info(line) cmd_api.send(cmd_name, *cmd_args) except IOError: log.error("Could not open '%s' for reading." % filename) log.end()
try: longopts = ["%s=" % key for key in options.keys()] opts, args = getopt.getopt(argv, "", longopts) for key, value in opts: if key.startswith("--"): key = key[2:] options[key] = value except getopt.GetoptError, err: log.error(str(err)) usage(exit=True) for key in numeric: value = options[key] if type(value) is str: options[key] = util.toNumber(value) if options[key] is None: msg = "Option '%s': '%s' is not a number, using default '%s' instead." log.error(msg, key, value, defaults[key]) options[key] = defaults[key] return options, args def usage(exit=False): """usage([exit]) Prints the usage statement at the top of a Python program. A usage statement is any comment at the start of a line that begins with a double hash marks (##). The double hash marks are removed before
def testToNumberWithDefaultReturnNone(self): """Test toNumber with String and None return""" n = util.toNumber("Foo") self.assertIsNone(n)
def testToNumberWithStringAndDefaultSpecified(self): """Test toNumber with String and new default specified""" n = util.toNumber("Foo", 42) self.assertIsInstance(n, int) self.assertEqual(n, 42)
def testToNumberWithFloat(self): """Test toNumber with float specified""" n = util.toNumber("42.0") self.assertIsInstance(n, float) self.assertEqual(n, 42.0)
def testToNumberWithInt(self): """Test toNumber with int specified""" n = util.toNumber("42") self.assertIsInstance(n, int) self.assertEqual(n, 42)
def testToNumberWithHex(self): """Test toNumber with Hex specified""" n = util.toNumber("0x2A") self.assertIsInstance(n, int) self.assertEqual(n, 42)