From 84d12b2a4cc7884c4e0544a2e7c8b6a104822459 Mon Sep 17 00:00:00 2001 From: olii Date: Thu, 4 Mar 2021 11:34:12 +0100 Subject: [PATCH] Fix parsing of lists with relativedelta objects. The relativedelta objects were rejected because we cannot compare them to strings. Both `==` and `!=` results to `False`. Instead we have to first test the type and then do the comparison. --- pyhocon/config_parser.py | 35 +++++++++++++++++++++++++++-------- tests/test_config_parser.py | 10 ++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/pyhocon/config_parser.py b/pyhocon/config_parser.py index 6acb4dd4..347461e0 100644 --- a/pyhocon/config_parser.py +++ b/pyhocon/config_parser.py @@ -63,6 +63,13 @@ def glob(pathname, recursive=False): else: from glob import glob + +try: + from dateutil.relativedelta import relativedelta as period_impl +except Exception: + from datetime import timedelta as period_impl + + logger = logging.getLogger(__name__) # @@ -87,11 +94,6 @@ class STR_SUBSTITUTION(object): def period(period_value, period_unit): - try: - from dateutil.relativedelta import relativedelta as period_impl - except Exception: - from datetime import timedelta as period_impl - if period_unit == 'nanoseconds': period_unit = 'microseconds' period_value = int(period_value / 1000) @@ -749,9 +751,26 @@ def postParse(self, instring, loc, token_list): :param token_list: :return: """ - cleaned_token_list = [token for tokens in (token.tokens if isinstance(token, ConfigInclude) else [token] - for token in token_list if token != '') - for token in tokens] + cleaned_token_list = [] + + # Note that: + # relativedelta.__eq__() raises NotImplemented if it is compared with + # a different object type so Python falls back to identity comparison. + # We cannot compare this object to a string. + # >>> relativedelta(hours = 1) == '' + # False + # >>> relativedelta(hours = 1) != '' + # False + for token in token_list: + # This is the case when there was a trailing comma in the list. + # The last token is just an empty string. + if isinstance(token, str) and token == '': + continue + if isinstance(token, ConfigInclude): + cleaned_token_list.extend(token.tokens) + else: + cleaned_token_list.append(token) + config_list = ConfigList(cleaned_token_list) return [config_list] diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py index a33e8029..10e7932e 100644 --- a/tests/test_config_parser.py +++ b/tests/test_config_parser.py @@ -148,6 +148,16 @@ def test_parse_string_with_duration_with_long_unit_name(self): ) assert config['b'] == period(weeks=10) + def test_parse_with_list_mixed_types_with_durations_and_trailing_comma(self): + config = ConfigFactory.parse_string( + """ + a: foo + b: [a, 1, 10 weeks, 5 minutes,] + c: bar + """ + ) + assert config['b'] == ['a', 1, period(weeks=10), period(minutes=5)] + def test_parse_with_enclosing_square_bracket(self): config = ConfigFactory.parse_string("[1, 2, 3]") assert config == [1, 2, 3]