Repository: fonttools/openstep-plist

Issue:
Support Glyphs-style "tuples"
Glyphs 3 plist files have "tuples" which appear on a single line even when other lines are separated/indented. The easiest way to support this would be to remove the `if indent is not None...` blocks from `write_array_from_tuple`. However, this may have Unintended Consequences.

Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools) Report
> :exclamation: No coverage uploaded for pull request base (`master@0e58a15`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools#section-missing-base-commit).
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/fonttools/openstep-plist/pull/7/graphs/tree.svg?width=650&height=150&src=pr&token=RD1iuhQfvT&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools)](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools)

```diff
@@            Coverage Diff            @@
##             master       #7   +/-   ##
=========================================
  Coverage          ?   93.19%           
=========================================
  Files             ?        5           
  Lines             ?      838           
  Branches          ?        6           
=========================================
  Hits              ?      781           
  Misses            ?       57           
  Partials          ?        0           
```


| [Impacted Files](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools) | Coverage Δ | |
|---|---|---|
| [src/openstep\_plist/writer.pyx](https://codecov.io/gh/fonttools/openstep-plist/pull/7/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools#diff-c3JjL29wZW5zdGVwX3BsaXN0L3dyaXRlci5weXg=) | `98.68% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools). Last update [0e58a15...d67d67e](https://codecov.io/gh/fonttools/openstep-plist/pull/7?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fonttools).


Patch:
diff --git a/src/openstep_plist/writer.pyx b/src/openstep_plist/writer.pyx
index b0b9034..b6cc262 100644
--- a/src/openstep_plist/writer.pyx
+++ b/src/openstep_plist/writer.pyx
@@ -114,9 +114,14 @@ cdef class Writer:
     cdef int float_precision
     cdef unicode indent
     cdef int current_indent_level
+    cdef bint single_line_tuples
 
     def __cinit__(
-        self, bint unicode_escape=True, int float_precision=6, indent=None
+        self,
+        bint unicode_escape=True,
+        int float_precision=6,
+        indent=None,
+        bint single_line_tuples=False,
     ):
         self.dest = array.clone(unicode_array_template, 0, zero=False)
         self.unicode_escape = unicode_escape
@@ -129,6 +134,7 @@ cdef class Writer:
                 self.indent = ' ' * indent
         else:
             self.indent = None
+        self.single_line_tuples = single_line_tuples
         self.current_indent_level = 0
 
     def getvalue(self):
@@ -433,7 +439,7 @@ cdef class Writer:
         count = 1
 
         indent = self.indent
-        if indent is not None:
+        if indent is not None and not self.single_line_tuples:
             self.current_indent_level += 1
             newline_indent = '\n' + self.current_indent_level * indent
             indent_length = PyUnicode_GET_SIZE(newline_indent)
@@ -450,10 +456,13 @@ cdef class Writer:
                     count += 2
                 else:
                     dest.append(',')
+                    if self.single_line_tuples:
+                        dest.append(' ')
+                        count += 1
                     array.extend_buffer(dest, <char*>indent_chars, indent_length)
                     count += 1 + indent_length
 
-        if indent is not None:
+        if indent is not None and not self.single_line_tuples:
             self.current_indent_level -= 1
             newline_indent = '\n' + self.current_indent_level * indent
             indent_length = PyUnicode_GET_SIZE(newline_indent)
@@ -594,21 +603,25 @@ cdef class Writer:
         return count
 
 
-def dumps(obj, bint unicode_escape=True, int float_precision=6, indent=None):
+def dumps(obj, bint unicode_escape=True, int float_precision=6, indent=None,
+          single_line_tuples=False):
     w = Writer(
         unicode_escape=unicode_escape,
         float_precision=float_precision,
         indent=indent,
+        single_line_tuples=single_line_tuples,
     )
     w.write(obj)
     return w.getvalue()
 
 
-def dump(obj, fp, bint unicode_escape=True, int float_precision=6, indent=None):
+def dump(obj, fp, bint unicode_escape=True, int float_precision=6, indent=None,
+         single_line_tuples=False):
     w = Writer(
         unicode_escape=unicode_escape,
         float_precision=float_precision,
         indent=indent,
+        single_line_tuples=single_line_tuples,
     )
     w.write(obj)
     w.dump(fp)


Test patch:
diff --git a/tests/test_writer.py b/tests/test_writer.py
index aafa043..77deabc 100644
--- a/tests/test_writer.py
+++ b/tests/test_writer.py
@@ -269,3 +269,25 @@ invalid_unquoted_chars = [
 )
 def test_string_needs_quotes(string, expected):
     assert string_needs_quotes(string) is expected
+
+
+def test_single_line_tuples():
+    assert openstep_plist.dumps({"a": 1, "b": (2, 3), "c": "Hello"}, indent=0) == (
+        """{
+a = 1;
+b = (
+2,
+3
+);
+c = Hello;
+}"""
+    )
+    assert openstep_plist.dumps(
+        {"a": 1, "b": (2, 3), "c": "Hello"}, indent=0, single_line_tuples=True
+    ) == (
+        """{
+a = 1;
+b = (2, 3);
+c = Hello;
+}"""
+    )