diff --git a/gura/GuraParser.py b/gura/GuraParser.py index db085b5..68aa79b 100644 --- a/gura/GuraParser.py +++ b/gura/GuraParser.py @@ -286,7 +286,8 @@ def primitive_type(self): :return: The corresponding matched value """ self.maybe_match('ws') - return self.match('null', 'boolean', 'basic_string', 'literal_string', 'number', 'variable_value') + return self.match('null', 'boolean', 'basic_string', 'literal_string', 'number', 'variable_value', + 'empty_object') def complex_type(self) -> Optional[Tuple[List, Dict]]: """ @@ -516,12 +517,20 @@ def __get_last_indentation_level(self) -> Optional[int]: def null(self) -> MatchResult: """ - Consumes null keyword and return None + Consumes 'null' keyword and returns None :return None """ self.keyword('null') return MatchResult(MatchResultType.PRIMITIVE, None) + def empty_object(self) -> MatchResult: + """ + Consumes 'empty' keyword and returns an empty object + :return Empty dict (which represents an object) + """ + self.keyword('empty') + return MatchResult(MatchResultType.PRIMITIVE, {}) + def boolean(self) -> MatchResult: """ Parses boolean values @@ -692,17 +701,21 @@ def dumps(self, value, indentation_level: int, new_line: bool) -> str: if value_type == bool: return ('true' if value is True else 'false') + new_line_char if value_type == dict: - result = '' - indentation = ' ' * (indentation_level * 4) - for key, dict_value in value.items(): - result += f'{indentation}{key}:' - # If it is an object it does not add a whitespace after key - if type(dict_value) != dict: - result += ' ' + if len(value) > 0: + result = '' + indentation = ' ' * (indentation_level * 4) + for key, dict_value in value.items(): + result += f'{indentation}{key}:' + # If it is an object it does not add a whitespace after key + if type(dict_value) != dict: + result += ' ' + + result += self.dumps(dict_value, indentation_level + 1, new_line=True) + return '\n' + result - result += self.dumps(dict_value, indentation_level + 1, new_line=True) + # Empty object + return ' empty\n' - return '\n' + result if value_type == list: # Lists are a special case: if it has an object, and indented representation must be returned. In case # of primitive values or nested arrays, a plain representation is more appropriated diff --git a/gura/__init__.py b/gura/__init__.py index e58e11a..fc0d225 100644 --- a/gura/__init__.py +++ b/gura/__init__.py @@ -2,7 +2,7 @@ VariableNotDefinedError, DuplicatedImportError, loads, dumps from gura.Parser import ParseError -__version__ = "1.2.0" +__version__ = "1.3.0" loads = loads dumps = dumps diff --git a/setup.py b/setup.py index 9def30f..6121bca 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ author='JWare', author_email='jware.organization@gmail.com', url='https://github.com/gura-conf/gura-python-parser', - download_url='https://github.com/gura-conf/gura-python-parser/archive/refs/tags/1.2.0.tar.gz', + download_url='https://github.com/gura-conf/gura-python-parser/archive/refs/tags/1.3.0.tar.gz', keywords=['Gura', 'parser', 'loads', 'dumps', 'encode', 'decode'], install_requires=[ 'wheel' diff --git a/tests/full/test.py b/tests/full/test.py index 8b7b9a3..81689c5 100644 --- a/tests/full/test.py +++ b/tests/full/test.py @@ -39,6 +39,7 @@ def setUp(self): "sf2": math.inf, "sf3": -math.inf, "null": None, + "empty_single": {}, "bool1": True, "bool2": False, "1234": "1234", @@ -81,6 +82,7 @@ def setUp(self): ], "my_server": { "host": "127.0.0.1", + "empty_nested": {}, "port": 8080, "native_auth": True }, diff --git a/tests/full/tests-files/full.ura b/tests/full/tests-files/full.ura index 1e0e6be..9a2cdf3 100644 --- a/tests/full/tests-files/full.ura +++ b/tests/full/tests-files/full.ura @@ -40,6 +40,9 @@ sf3: -inf # Negative infinity # Null null: null +# Empty objects +empty_single: empty + # Bool bool1: true bool2: false @@ -91,6 +94,7 @@ $my_integer_var: 8080 my_server: host: $my_string_var + empty_nested: empty port: $my_integer_var native_auth: true diff --git a/tests/objects/test.py b/tests/objects/test.py index a9f19ce..432ed90 100644 --- a/tests/objects/test.py +++ b/tests/objects/test.py @@ -8,6 +8,7 @@ class TestObjectsGura(unittest.TestCase): file_dir: str expected: Dict + empty_object: Dict def setUp(self): self.file_dir = os.path.dirname(os.path.abspath(__file__)) @@ -30,6 +31,10 @@ def setUp(self): } } + self.empty_object = { + 'empty_object': {} + } + def __get_file_parsed_data(self, file_name) -> Dict: """ Gets the content of a specific file parsed @@ -46,6 +51,21 @@ def test_normal(self): parsed_data = self.__get_file_parsed_data('normal.ura') self.assertDictEqual(parsed_data, self.expected) + def test_empty(self): + """Tests empty object""" + parsed_data = gura.loads('empty_object: empty') + self.assertDictEqual(parsed_data, self.empty_object) + + def test_empty_2(self): + """Tests empty object with several blanks""" + parsed_data = gura.loads('empty_object: empty ') + self.assertDictEqual(parsed_data, self.empty_object) + + def test_empty_3(self): + """Tests empty object with comments and blank lines""" + parsed_data = self.__get_file_parsed_data('empty.ura') + self.assertDictEqual(parsed_data, self.empty_object) + def test_with_comments(self): """Tests all kind of objects with comments between elements""" parsed_data = self.__get_file_parsed_data('with_comments.ura') diff --git a/tests/objects/tests-files/empty.ura b/tests/objects/tests-files/empty.ura new file mode 100644 index 0000000..8026c08 --- /dev/null +++ b/tests/objects/tests-files/empty.ura @@ -0,0 +1,6 @@ +# COMMMENT +empty_object: empty + + + +# COMMENT