diff --git a/pyhocon/config_parser.py b/pyhocon/config_parser.py index 653321e5..b1dfbeb2 100644 --- a/pyhocon/config_parser.py +++ b/pyhocon/config_parser.py @@ -110,7 +110,6 @@ class STR_SUBSTITUTION(object): U_KEY_SEP = unicode('.') U_KEY_FMT = unicode('"{0}"') - U_KEY_SEP = unicode('.') U_KEY_FMT = unicode('"{0}"') @@ -386,7 +385,8 @@ def set_default_white_spaces(): true_expr = Keyword("true", caseless=True).setParseAction(replaceWith(True)) false_expr = Keyword("false", caseless=True).setParseAction(replaceWith(False)) null_expr = Keyword("null", caseless=True).setParseAction(replaceWith(NoneValue())) - key = QuotedString('"', escChar='\\', unquoteResults=False) | Word(alphanums + alphas8bit + '._- /') + key = QuotedString('"""', escChar='\\', unquoteResults=False) | \ + QuotedString('"', escChar='\\', unquoteResults=False) | Word(alphanums + alphas8bit + '._- /') eol = Word('\n\r').suppress() eol_comma = Word('\n\r,').suppress() diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py index 63f90795..316f4bb8 100644 --- a/tests/test_config_parser.py +++ b/tests/test_config_parser.py @@ -40,10 +40,13 @@ def test_parse_simple_value(self): "first line" "second" line \"\"\" + \"\"\"z\"\"\": sample } j = [1, 2, 3] u = 192.168.1.3/32 g = null + \"\"\"z\"\"\" = 1 + \"\"\"z2\"\"\": 21 } """ ) @@ -52,6 +55,7 @@ def test_parse_simple_value(self): assert config.get_int('t.c') == 5 assert config.get_float('t.c') == 5.0 assert config.get('t.e.y.f') == 7 + assert config.get('t.e.y.z') == 'sample' assert config.get('t.e.y.g') == 'hey dude!' assert config.get('t.e.y.h') == 'hey man' assert [v.strip() for v in config.get('t.e.y.i').split('\n')] == ['', '"first line"', '"second" line', ''] @@ -65,6 +69,8 @@ def test_parse_simple_value(self): assert config.get_bool('t.g') is None assert config.get_list('t.g') is None assert config.get_config('t.g') is None + assert config.get('t.z') == 1 + assert config.get('t.z2') == 21 @pytest.mark.parametrize('forbidden_char', ['+', '`', '^', '?', '!', '@', '*', '&']) def test_fail_parse_forbidden_characters(self, forbidden_char): @@ -2626,6 +2632,22 @@ def test_escape_sequences_json_equivalence(self): assert config == expected assert config == json.loads(source) + def test_triple_quotes_keys(self): + config = ConfigFactory.parse_string("\"\"\"foo\"\"\" = bar") + assert config['foo'] == 'bar' + + def test_triple_quotes_keys_triple_quotes_values(self): + config = ConfigFactory.parse_string("\"\"\"foo\"\"\" = \"\"\"bar\"\"\"") + assert config['foo'] == 'bar' + + def test_triple_quotes_keys_second_separator(self): + config = ConfigFactory.parse_string("\"\"\"foo\"\"\": bar") + assert config['foo'] == 'bar' + + def test_triple_quotes_keys_triple_quotes_values_second_separator(self): + config = ConfigFactory.parse_string("\"\"\"foo\"\"\": \"\"\"bar\"\"\"") + assert config['foo'] == 'bar' + try: from dateutil.relativedelta import relativedelta