Slighlty changed command arguments parser/adapter internal logic

Made parser to preserve the order of options, so I can use it later to provide
some enhancments for the adapter.
This commit is contained in:
red-agent 2009-09-15 01:20:49 +03:00
parent 7bec311cfb
commit a264608b29
1 changed files with 31 additions and 31 deletions

View File

@ -382,8 +382,9 @@ class CommandProcessor(object):
def parse_command_arguments(cls, arguments): def parse_command_arguments(cls, arguments):
""" """
Simple yet effective and sufficient in most cases parser which parses Simple yet effective and sufficient in most cases parser which parses
command arguments and maps them to *args and **kwargs, which we all use command arguments and returns them as two lists, first representing
extensivly in daily Python coding. positional arguments, and second representing options as (key, value)
tuples.
The format of the input arguments should be: The format of the input arguments should be:
<arg1, arg2> <<optional>> [-(-o)ption=value1, -(-a)nother=value2] [[extra_options]] <arg1, arg2> <<optional>> [-(-o)ption=value1, -(-a)nother=value2] [[extra_options]]
@ -394,37 +395,38 @@ class CommandProcessor(object):
'one two three' or "one two three"; that is between single or double 'one two three' or "one two three"; that is between single or double
quotes. quotes.
""" """
args, kwargs = [], {} args, opts = [], []
# Need to store every option we have parsed in order to get arguments # Need to store position of every option we have parsed in order to get
# to be parsed correct later. # arguments to be parsed correct later.
options = [] opt_positions = []
def intersects((given_start, given_end)): def intersects((given_start, given_end)):
""" """
Check if something intersects with boundaries of any parsed options. Check if something intersects with boundaries of any parsed options.
""" """
for start, end in options: for start, end in opt_positions:
if given_start == start or given_end == end: if given_start == start or given_end == end:
return True return True
return False return False
for match in re.finditer(cls.OPT_PATTERN, arguments): for match in re.finditer(cls.OPT_PATTERN, arguments):
if match: if match:
options.append(match.span()) opt_positions.append(match.span())
kwargs[match.group('key')] = match.group('value') or True opts.append((match.group('key'), match.group('value') or True))
for match in re.finditer(cls.ARG_PATTERN, arguments): for match in re.finditer(cls.ARG_PATTERN, arguments):
if match and not intersects(match.span()): if match and not intersects(match.span()):
args.append(match.group('body')) args.append(match.group('body'))
return args, kwargs return args, opts
@classmethod @classmethod
def adapt_command_arguments(cls, command, arguments, args, kwargs): def adapt_command_arguments(cls, command, arguments, args, opts):
""" """
Adapts *args and **kwargs got from a parser to a specific handler by Adapts args and opts got from the parser to a specific handler by means
means of arguments specified on command definition. of arguments specified on command definition. That is transforms them to
*args and **kwargs suitable for passing to a command handler.
When EXPAND_SHORT_OPTIONS is set then if command receives one-latter When EXPAND_SHORT_OPTIONS is set then if command receives one-latter
options (like -v or -f) they will be expanded to a verbose ones (like options (like -v or -f) they will be expanded to a verbose ones (like
@ -467,35 +469,33 @@ class CommandProcessor(object):
raise CommandInternalError("Cant have both, __optional__ and *args") raise CommandInternalError("Cant have both, __optional__ and *args")
if command.dashes: if command.dashes:
for key, value in kwargs.items(): for index, (key, value) in enumerate(opts):
if '-' in key: if '-' in key:
del kwargs[key] opts[index] = (key.replace('-', '_'), value)
kwargs[key.replace('-', '_')] = value
if cls.EXPAND_SHORT_OPTIONS: if cls.EXPAND_SHORT_OPTIONS:
expanded = [] expanded = []
for key, value in spec_kwargs.iteritems(): for spec_key, spec_value in spec_kwargs.iteritems():
letter = key[0] if len(key) > 1 else None letter = spec_key[0] if len(spec_key) > 1 else None
if letter and letter in kwargs and letter not in expanded: if letter and letter not in expanded:
expanded.append(letter) for index, (key, value) in enumerate(opts):
kwargs[key] = kwargs[letter] if key == letter:
del kwargs[letter] expanded.append(letter)
opts[index] = (spec_key, value)
break
# We need to encode every keyword argument to a simple string, not the # We need to encode every keyword argument to a simple string, not the
# unicode one, because ** expanding does not support it. The nasty issue # unicode one, because ** expanding does not support it.
# here to consider is that if dict key was initially set as u'test', for index, (key, value) in enumerate(opts):
# then resetting it to just 'test' leaves u'test' as it was...
for key, value in kwargs.items():
if isinstance(key, UnicodeType): if isinstance(key, UnicodeType):
del kwargs[key] opts[index] = (key.encode(cls.ARG_ENCODING), value)
kwargs[key.encode(cls.ARG_ENCODING)] = value
if '__arguments__' in spec_args: if '__arguments__' in spec_args:
if len(spec_args) == 1 and not spec_kwargs and not var_args and not var_kwargs: if len(spec_args) == 1 and not spec_kwargs and not var_args and not var_kwargs:
return (arguments,), {} return (arguments,), {}
args.insert(spec_args.index('__arguments__'), arguments) args.insert(spec_args.index('__arguments__'), arguments)
return args, kwargs return tuple(args), dict(opts)
def process_as_command(self, text): def process_as_command(self, text):
""" """
@ -526,8 +526,8 @@ class CommandProcessor(object):
def execute_command(self, name, arguments): def execute_command(self, name, arguments):
command = self.retrieve_command(name) command = self.retrieve_command(name)
args, kwargs = self.parse_command_arguments(arguments) if arguments else ([], {}) args, opts = self.parse_command_arguments(arguments) if arguments else ([], [])
args, kwargs = self.adapt_command_arguments(command, arguments, args, kwargs) args, kwargs = self.adapt_command_arguments(command, arguments, args, opts)
if self.command_preprocessor(name, command, arguments, args, kwargs): if self.command_preprocessor(name, command, arguments, args, kwargs):
return return