From 7fd79f7451233975057cf36197687d4cbbd82554 Mon Sep 17 00:00:00 2001 From: AlexanderFromEarth Date: Mon, 21 Nov 2022 20:06:09 +0500 Subject: [PATCH 1/4] feat(encoder): add support for preserving list of inline tables --- toml/encoder.py | 25 ++++++++++++++++++++++--- toml/encoder.pyi | 3 ++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/toml/encoder.py b/toml/encoder.py index bf17a72..2b7722f 100644 --- a/toml/encoder.py +++ b/toml/encoder.py @@ -154,7 +154,7 @@ def dump_list(self, v): retval += "]" return retval - def dump_inline_table(self, section): + def dump_inline_table(self, section, with_newline=True): """Preserve inline table in its compact syntax instead of expanding into subsection. @@ -166,14 +166,21 @@ def dump_inline_table(self, section): for k, v in section.items(): val = self.dump_inline_table(v) val_list.append(k + " = " + val) - retval += "{ " + ", ".join(val_list) + " }\n" + retval += "{ " + ", ".join(val_list) + " }" + + if with_newline: + retval += "\n" + return retval else: return unicode(self.dump_value(section)) + def dump_inline_table_value(self, value): + return self.dump_inline_table(value, False) + def dump_value(self, v): # Lookup function corresponding to v's type - dump_fn = self.dump_funcs.get(type(v)) + dump_fn = self.dump_inline_table_value if isinstance(v, InlineTableDict) else self.dump_funcs.get(type(v)) if dump_fn is None and hasattr(v, '__iter__'): dump_fn = self.dump_funcs[list] # Evaluate function (if it exists) else return v @@ -192,11 +199,23 @@ def dump_sections(self, o, sup): qsection = _dump_str(section) if not isinstance(o[section], dict): arrayoftables = False + inlines = [] + if isinstance(o[section], list): for a in o[section]: if isinstance(a, dict): arrayoftables = True if arrayoftables: + for a in o[section]: + if isinstance(a, InlineTableDict): + inlines.append(a) + + if self.preserve and len(inlines) == len(o[section]): + retstr += (qsection + " = " + + unicode(self.dump_value(o[section])) + '\n') + + continue + for a in o[section]: arraytabstr = "\n" arraystr += "[[" + sup + qsection + "]]\n" diff --git a/toml/encoder.pyi b/toml/encoder.pyi index 194a358..5d2c754 100644 --- a/toml/encoder.pyi +++ b/toml/encoder.pyi @@ -12,7 +12,8 @@ class TomlEncoder: def __init__(self, _dict: Any = ..., preserve: bool = ...): ... def get_empty_table(self): ... def dump_list(self, v: Any): ... - def dump_inline_table(self, section: Any): ... + def dump_inline_table(self, section: Any, with_newline: bool = ...): ... + def dump_inline_table_value(self, section: Any): ... def dump_value(self, v: Any): ... def dump_sections(self, o: Any, sup: Any): ... From 12599c8966428c62e03959857a83780bb341a331 Mon Sep 17 00:00:00 2001 From: AlexanderFromEarth Date: Mon, 21 Nov 2022 20:12:34 +0500 Subject: [PATCH 2/4] styles(encoder): fix quotes --- toml/encoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toml/encoder.py b/toml/encoder.py index 2b7722f..a66b26e 100644 --- a/toml/encoder.py +++ b/toml/encoder.py @@ -212,7 +212,7 @@ def dump_sections(self, o, sup): if self.preserve and len(inlines) == len(o[section]): retstr += (qsection + " = " + - unicode(self.dump_value(o[section])) + '\n') + unicode(self.dump_value(o[section])) + "\n") continue From adf6bbe14266edc14de21bc48e0c047dd264fb84 Mon Sep 17 00:00:00 2001 From: AlexanderFromEarth Date: Mon, 21 Nov 2022 20:32:26 +0500 Subject: [PATCH 3/4] refactor(encoder): extract to separate parameter --- toml/encoder.py | 21 +++++++++++---------- toml/encoder.pyi | 11 ++++++----- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/toml/encoder.py b/toml/encoder.py index a66b26e..44f9a43 100644 --- a/toml/encoder.py +++ b/toml/encoder.py @@ -128,9 +128,10 @@ def _dump_time(v): class TomlEncoder(object): - def __init__(self, _dict=dict, preserve=False): + def __init__(self, _dict=dict, preserve=False, preserve_list=False): self._dict = _dict self.preserve = preserve + self.preserve_list = preserve_list self.dump_funcs = { str: _dump_str, unicode: _dump_str, @@ -210,7 +211,7 @@ def dump_sections(self, o, sup): if isinstance(a, InlineTableDict): inlines.append(a) - if self.preserve and len(inlines) == len(o[section]): + if self.preserve_list and len(inlines) == len(o[section]): retstr += (qsection + " = " + unicode(self.dump_value(o[section])) + "\n") @@ -254,14 +255,14 @@ def dump_sections(self, o, sup): class TomlPreserveInlineDictEncoder(TomlEncoder): - def __init__(self, _dict=dict): - super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True) + def __init__(self, _dict=dict, preserve_list=False): + super(TomlPreserveInlineDictEncoder, self).__init__(_dict, True, preserve_list) class TomlArraySeparatorEncoder(TomlEncoder): - def __init__(self, _dict=dict, preserve=False, separator=","): - super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve) + def __init__(self, _dict=dict, preserve=False, separator=",", preserve_list=False): + super(TomlArraySeparatorEncoder, self).__init__(_dict, preserve, preserve_list) if separator.strip() == "": separator = "," + separator elif separator.strip(' \t\n\r,'): @@ -288,9 +289,9 @@ def dump_list(self, v): class TomlNumpyEncoder(TomlEncoder): - def __init__(self, _dict=dict, preserve=False): + def __init__(self, _dict=dict, preserve=False, preserve_list=False): import numpy as np - super(TomlNumpyEncoder, self).__init__(_dict, preserve) + super(TomlNumpyEncoder, self).__init__(_dict, preserve, preserve_list) self.dump_funcs[np.float16] = _dump_float self.dump_funcs[np.float32] = _dump_float self.dump_funcs[np.float64] = _dump_float @@ -304,9 +305,9 @@ def _dump_int(self, v): class TomlPreserveCommentEncoder(TomlEncoder): - def __init__(self, _dict=dict, preserve=False): + def __init__(self, _dict=dict, preserve=False, preserve_list=False): from toml.decoder import CommentValue - super(TomlPreserveCommentEncoder, self).__init__(_dict, preserve) + super(TomlPreserveCommentEncoder, self).__init__(_dict, preserve, preserve_list) self.dump_funcs[CommentValue] = lambda v: v.dump(self.dump_value) diff --git a/toml/encoder.pyi b/toml/encoder.pyi index 5d2c754..f8b12be 100644 --- a/toml/encoder.pyi +++ b/toml/encoder.pyi @@ -8,8 +8,9 @@ def dumps(o: Mapping[str, Any], encoder: TomlEncoder = ...) -> str: ... class TomlEncoder: preserve: Any = ... + preserve_list: Any = ... dump_funcs: Any = ... - def __init__(self, _dict: Any = ..., preserve: bool = ...): ... + def __init__(self, _dict: Any = ..., preserve: bool = ..., preserve_list: bool = ...): ... def get_empty_table(self): ... def dump_list(self, v: Any): ... def dump_inline_table(self, section: Any, with_newline: bool = ...): ... @@ -18,18 +19,18 @@ class TomlEncoder: def dump_sections(self, o: Any, sup: Any): ... class TomlPreserveInlineDictEncoder(TomlEncoder): - def __init__(self, _dict: Any = ...) -> None: ... + def __init__(self, _dict: Any = ..., preserve_list: bool = ...) -> None: ... class TomlArraySeparatorEncoder(TomlEncoder): separator: Any = ... - def __init__(self, _dict: Any = ..., preserve: bool = ..., separator: str = ...) -> None: ... + def __init__(self, _dict: Any = ..., preserve: bool = ..., separator: str = ..., preserve_list: bool = ...) -> None: ... def dump_list(self, v: Any): ... class TomlNumpyEncoder(TomlEncoder): - def __init__(self, _dict: Any = ..., preserve: bool = ...) -> None: ... + def __init__(self, _dict: Any = ..., preserve: bool = ..., preserve_list: bool = ...) -> None: ... class TomlPreserveCommentEncoder(TomlEncoder): - def __init__(self, _dict: Any = ..., preserve: bool = ...): ... + def __init__(self, _dict: Any = ..., preserve: bool = ..., preserve_list: bool = ...): ... class TomlPathlibEncoder(TomlEncoder): def dump_value(self, v: Any): ... From d95b70bbbd8d9b02b1e2062ec187ef5e896a064a Mon Sep 17 00:00:00 2001 From: AlexanderFromEarth Date: Mon, 21 Nov 2022 20:35:24 +0500 Subject: [PATCH 4/4] tests(encoder): add test string for list of inline tables --- tests/test_api.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_api.py b/tests/test_api.py index 1acc26f..38f0279 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -280,3 +280,15 @@ def test_deepcopy_timezone(): o2 = copy.deepcopy(o) assert o2["dob"] == o["dob"] assert o2["dob"] is not o["dob"] + + +def test_list_of_inline_tables_with_preserve(): + test_str = """[[test]] +x = [ { name = "test1" }, { name = "test2" },] + +""" + s = toml.dumps(toml.loads(test_str, + decoder=toml.TomlDecoder()), + encoder=toml.TomlEncoder(preserve_list=True)) + + assert len(s) == len(test_str) and sorted(test_str) == sorted(s)