Source code for parmed.tools.argumentlist

"""
This stores a list of arguments, tokenizing a string into a list of arguments.
"""
import logging
import warnings
from .exceptions import NoArgument, InputError

LOGGER = logging.getLogger(__name__)

[docs]class Argument(object): """ Is an argument """ def __init__(self, string): """ Input string for the argument """ self.string = string.strip() self.marked = False self.keep_quotes = False if len(string) == 0 or (len(string) == 1 and string in ("'", '"')): LOGGER.warning("Unclosed quotation detected! Ignoring lone quote")
[docs] def lower(self): """ Make the argument lower-case """ return self.string.lower()
[docs] def isfloat(self): """ Determines if it can be a double """ try: tmp = float(self.string) del tmp return True except ValueError: return False
[docs] def isint(self): """ Determines if it can be an integer """ try: tmp = int(self.string) del tmp return True except ValueError: return False
[docs] def ismask(self): """ Determines if we can be an Amber mask or not """ # The easiest way to do this is to just search for ":" or "@" in the # input string (or just the string *, which matches everything). return self.string == '*' or ':' in self.string or '@' in self.string
# Define some casting behavior def __float__(self): self.marked = True return float(self.string) def __int__(self): self.marked = True return int(self.string) def __str__(self): self.marked = True if self.keep_quotes: return self.string # Strip leading and trailing quotes (only if they both exist) if self.string[0] == "'" and self.string[-1] == "'": return self.string[1:-1] elif self.string[0] == '"' and self.string[-1] == '"': return self.string[1:len(self.string)-1] return self.string def __eq__(self, other): """ String comparison """ return self.string == str(other)
[docs] def mark(self): """ Provide a way of forcibly marking an argument """ self.marked = True
[docs] def unmark(self): """ Provide a way of forcibly unmarking an argument """ self.marked = False
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
[docs]class ArgumentList(object): """ List of arguments. The arguments should be parsed in the following order to ensure it's done correctly: get_key_* get_next_int get_next_float get_next_mask get_next_string """ def __init__(self, inp): """ Defines the string """ if isinstance(inp, tuple) or isinstance(inp, list): _inp = [l for l in inp if l is not None and l != ''] self.original = ' '.join([str(l) for l in _inp]) self.tokenlist = [Argument(str(l)) for l in _inp] elif isinstance(inp, ArgumentList): self.tokenlist = [] try: while True: arg = Argument(inp.get_next_string()) self.tokenlist.append(arg) except NoArgument: pass self.original = ' '.join([str(a) for a in inp.tokenlist]) else: # Treat as a string-like and pad with spaces self.original = ' %s ' % inp self.tokenize(self.original)
[docs] def tokenize(self, instring): """ Tokenizes the line, everything between quotes is a single token, including whitespace """ import re tokenre = re.compile(r'''((?:\s+".*?"\s+?)|(?:\s+'.*?'\s+?)|(?:\S+))''') tokenlist = tokenre.findall(instring) # Make sure every non-whitespace character is consumed if len(tokenre.sub('', instring).strip()) > 0: warnings.warn("Not all of argument string were handled: [%s]" % tokenre.sub('', instring).strip()) # Strip out whitespace in all arguments self.tokenlist = [Argument(token.strip()) for token in tokenlist]
def __str__(self): """ Return the original input string """ return self.original
[docs] def get_next_int(self, optional=False, default=None): """ Returns the next unmarked integer in the token list """ for token in self.tokenlist: if token.isint() and not token.marked: return int(token) if optional: return default raise NoArgument("Missing integer argument!")
[docs] def get_next_float(self, optional=False, default=None): """ Returns the next unmarked float in the token list """ for token in self.tokenlist: if token.isfloat() and not token.marked: return float(token) if optional: return default raise NoArgument("Missing floating point argument!")
[docs] def get_next_mask(self, optional=False, default=None): """ Returns the next string as long as it matches a mask """ for token in self.tokenlist: if token.marked: continue if token.ismask(): return str(token) if optional: return default raise NoArgument("Missing Amber mask!")
[docs] def get_next_string(self, optional=False, keep_quotes=False, default=None): """ Returns the next unmarked float in the token list """ for token in self.tokenlist: if not token.marked: token.keep_quotes = keep_quotes return str(token) if optional: return default raise NoArgument("Missing string!")
[docs] def unmarked(self): """ Returns all unmarked arguments as a list of strings """ unmarked_tokens = [] for token in self.tokenlist: if not token.marked: unmarked_tokens.append(token.string) return unmarked_tokens
def _get_key_arg(self, key, argtype): """ Gets a key with a given argument type """ for i, token in enumerate(self.tokenlist): # Skip all marked tokens. This allows us to allow users to specify # a token numerous times (useful if you want to enable an # arbitrary-length list of arguments if token.marked: continue if token == key: if self.tokenlist[i+1].marked: raise RuntimeError("Expected token already marked! Should " "not happen. This means a buggy " "action...") token.marked = True try: return argtype(self.tokenlist[i+1]) except ValueError as err: raise InputError(str(err)) raise NoArgument('Catch me!')
[docs] def get_key_int(self, key, default): """ Get an integer that follows a keyword """ try: return self._get_key_arg(key, int) except NoArgument: return default
[docs] def get_key_float(self, key, default): """ Get a float that follows a keyword """ try: return self._get_key_arg(key, float) except NoArgument: return default
[docs] def get_key_mask(self, key, default): """ Get a mask that follows a keyword """ for i, token in enumerate(self.tokenlist): if token == key: if not self.tokenlist[i+1].ismask(): raise InputError("Expected mask to follow %s. Got %s " "instead" % (key, self.tokenlist[i+1].string)) try: return self._get_key_arg(key, str) except NoArgument: return default
[docs] def get_key_string(self, key, default): """ Get a string that follows a keyword """ try: return self._get_key_arg(key, str) except NoArgument: return default
[docs] def has_key(self, key, mark=True): """ See if a particular keyword is present (optionally mark it) """ for token in self.tokenlist: if not token.marked and token == key: if mark: token.mark() return True return False