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:
parent
7bec311cfb
commit
a264608b29
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue