Merge pull request #44 from jakebasile/master

Escaping separators
This commit is contained in:
Jakub Roztocil 2012-04-24 07:25:17 -07:00
commit 29e594daaf
2 changed files with 55 additions and 6 deletions

View File

@ -1,6 +1,7 @@
import os
import json
import argparse
import re
from collections import namedtuple
from . import pretty
from . import __doc__ as doc
@ -31,23 +32,44 @@ class ParseError(Exception):
KeyValue = namedtuple('KeyValue', ['key', 'value', 'sep', 'orig'])
class KeyValueType(object):
"""A type used with `argparse`."""
def __init__(self, *separators):
self.separators = separators
self.escapes = ['\\\\' + sep for sep in separators]
def __call__(self, string):
found = dict((string.find(sep), sep)
for sep in self.separators
if string.find(sep) != -1)
found = {}
found_escapes = []
for esc in self.escapes:
found_escapes += [m.span() for m in re.finditer(esc, string)]
for sep in self.separators:
matches = re.finditer(sep, string)
for match in matches:
start, end = match.span()
inside_escape = False
for estart, eend in found_escapes:
if start >= estart and end <= eend:
inside_escape = True
break
if not inside_escape:
found[start] = sep
if not found:
#noinspection PyExceptionInherit
raise argparse.ArgumentTypeError(
'"%s" is not a valid value' % string)
sep = found[min(found.keys())]
key, value = string.split(sep, 1)
# split the string at the earliest non-escaped separator.
seploc = min(found.keys())
sep = found[seploc]
key = string[:seploc]
value = string[seploc + len(sep):]
# remove escape chars
for sepstr in self.separators:
key = key.replace('\\' + sepstr, sepstr)
value = value.replace('\\' + sepstr, sepstr)
return KeyValue(key=key, value=value, sep=sep, orig=string)

View File

@ -57,6 +57,33 @@ class TestItemParsing(BaseTest):
self.assertRaises(argparse.ArgumentTypeError,
lambda: self.kv(item))
def test_escape(self):
headers, data, files = cli.parse_items([
# headers
self.kv('foo\\:bar:baz'),
self.kv('jack\\@jill:hill'),
# data
self.kv('baz\\=bar=foo'),
# files
self.kv('bar\\@baz@%s' % TEST_FILE)
])
self.assertDictEqual(headers, {
'foo:bar': 'baz',
'jack@jill': 'hill',
})
self.assertDictEqual(data, {
'baz=bar': 'foo',
})
self.assertIn('bar@baz', files)
def test_escape_longsep(self):
headers, data, files = cli.parse_items([
self.kv('bob\\:==foo'),
])
self.assertDictEqual(data, {
'bob:=': 'foo',
})
def test_valid_items(self):
headers, data, files = cli.parse_items([
self.kv('string=value'),