Last active
August 29, 2015 14:11
-
-
Save xZise/75c482a5871f0b1cb55b to your computer and use it in GitHub Desktop.
Parser for advanced argparse values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# -*- coding: utf-8 -*- | |
from collections import OrderedDict | |
def parse_value(value, parameters, allow_unknown=False): | |
""" | |
Parse the value of an argument into subarguments. | |
The value is basically a comma-separated string. Each comma-separated value | |
can be named which is separated by an equals sign. It is possible to escape | |
both commas and equal signs. Any equal signs after a name must not be | |
escaped. The value may be unnamed but only if there aren't any named | |
parameters before it. | |
It must contain predefined parameters with a name and a default value if | |
the parameter is optional. | |
>>> params = OrderedDict((('title', (False, None)), ('type', (True, 'default')))) | |
>>> parse_value('foo,bar', params) | |
{'title': 'foo', 'type': 'bar'} | |
>>> parse_value('foo,type=bar', params) | |
{'title': 'foo', 'type': 'bar'} | |
>>> parse_value('title=foo,type=bar', params) | |
{'title': 'foo', 'type': 'bar'} | |
>>> parse_value('foo', params) | |
{'title': 'foo', 'type': 'default'} | |
>>> parse_value('foo,', params) | |
{'title': 'foo', 'type': ''} | |
# TODO: Those are invalid: Check their exceptions | |
>>> parse_value('title=foo,bar', params) | |
>>> parse_value('title=foo,title=bar', params) | |
>>> parse_value('foo,title=bar', params) | |
>>> parse_value('foo,=bar', params) | |
>>> parse_value('foo,unknown=bar', params) | |
@param value: The value which should be parsed | |
@type value: str | |
@param parameters: The predefined parameters mapping a name to a tuple | |
containing if it's optional and a default value when it's optional. | |
@type parameters: OrderedDict | |
@param allow_unknown: Allow values inside of value which are not defined | |
in parameters. | |
@type allow_unknown: bool | |
""" | |
name = None | |
escaped = False | |
buffer_value = '' | |
result = {} | |
parameter_number = 0 | |
value += ',' | |
for i in range(len(value)): | |
if not escaped: | |
if value[i] == '\\': | |
escaped = True | |
continue | |
elif value[i] == '=' and name is None: | |
name = buffer_value | |
buffer_value = '' | |
if not name: | |
# TODO: More specific exception | |
raise Exception('No parameter name was given') | |
elif name not in parameters and not allow_unknown: | |
raise Exception('The parameter {0} is not known.'.format(name)) | |
continue | |
elif value[i] == ',': | |
if name is None: | |
if parameter_number is False: | |
# TODO: Emulate closer argparse | |
raise Exception('Positional parameter after keyword') | |
name = parameters[parameter_number][0] | |
parameter_number += 1 | |
else: | |
parameter_number = False | |
if name in result: | |
raise Exception('The value for {0} is already defined.'.format(name)) | |
result[name] = buffer_value | |
buffer_value = '' | |
name = None | |
continue | |
buffer_value += value[i] | |
escaped = False | |
undefined = [n for n, p in parameters.items() if not p[0] and n not in result] | |
if undefined: | |
raise Exception('The required parameter(s) "{0}" are not defined.'.format('", "'.join(undefined))) | |
for default_name, default_value in parameters.items(): | |
if default_value[0] and default_name not in result: | |
result[default_name] = default_value[1] | |
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import traceback | |
parameters_exmpl = OrderedDict((('title', (False, None)), ('type', (True, 'default')))) | |
for arg in sys.argv[1:]: | |
print('Parsing "{}":'.format(arg)) | |
for allow in [False, True]: | |
print('Allow unknown: {}'.format(allow)) | |
try: | |
for result_line in sorted(parse_value(arg, parameters_exmpl, allow).items()): | |
print(' {}: {}'.format(*result_line)) | |
except Exception as e: | |
print('!! Exception occured') | |
traceback.print_exc() | |
print('') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment