Repository: pyout/pyout

Issue:
Make width as large as needed in "final" mode
If stdout it not a tty ATM pytout seems to limit to some predetermined width:
```shell
$> datalad ls -r ~/datalad -L | cat 
[3]  - 3355 done       gitk --all
PATH              TYPE  BRANCH DESCRIBE DATE          CLEAN ANNEX(PRESENT) ANNEX(WORKTREE)
/home/yoh/datalad annex master          2018-09-17... -     31.3 MB        23.8 MB        
/home/yoh/data... annex master 0.0.2... 2018-06-08... X     0 Bytes        0 Bytes        
/home/yoh/data... annex master          2018-06-08... X     0 Bytes        0 Bytes        
...
```
but since delivering the "final" rendering -- why not to make it as wide as needed?  
Also then It would correspond to the final version of the "update" mode output

Comments:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae31082..b55a868 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
   the proportion of the table.  For example, setting the "max" key to
   0.5 means that the key should exceed half of the total table width.
 
+- When operating non-interactively, by default the width is now
+  expanded to accommodate the content.  To force a particular table
+  width in this situation, set the table's width using the "width_"
+  style attribute.
 
 ## [0.4.1] - 2019-10-02
 
diff --git a/pyout/common.py b/pyout/common.py
index 0bf2484..0aaac98 100644
--- a/pyout/common.py
+++ b/pyout/common.py
@@ -371,6 +371,10 @@ class StyleFields(object):
         visible = self.visible_columns
         autowidth_columns = self.autowidth_columns
         width_table = self.style["width_"]
+        if width_table is None:
+            # The table is unbounded (non-interactive).
+            return
+
         if len(visible) > width_table:
             raise elements.StyleError(
                 "Number of visible columns exceeds available table width")
@@ -431,7 +435,10 @@ class StyleFields(object):
 
         width_table = self.style["width_"]
         width_fixed = self.width_fixed
-        width_auto = width_table - width_fixed
+        if width_table is None:
+            width_auto = float("inf")
+        else:
+            width_auto = width_table - width_fixed
 
         if not autowidth_columns:
             return False
@@ -502,7 +509,7 @@ class StyleFields(object):
                available characters the column should claim at a time.  This is
                only in effect after each column has claimed one, and the
                specific column has claimed its minimum.
-        available : int
+        available : int or float('inf')
             Width available to be assigned.
 
         Returns
@@ -551,7 +558,7 @@ class StyleFields(object):
                         claim, available, column)
                 if available == 0:
                     break
-        lgr.debug("Available width after assigned: %d", available)
+        lgr.debug("Available width after assigned: %s", available)
         lgr.debug("Assigned widths: %r", assigned)
         return assigned
 
diff --git a/pyout/elements.py b/pyout/elements.py
index 716a325..fef77f4 100644
--- a/pyout/elements.py
+++ b/pyout/elements.py
@@ -215,9 +215,13 @@ schema = {
             "scope": "table"},
         "width_": {
             "description": """Total width of table.
-            This is typically not set directly by the user.""",
-            "default": 90,
-            "type": "integer",
+            This is typically not set directly by the user.  With the default
+            null value, the width is set to the stream's width for interactive
+            streams and as wide as needed to fit the content for
+            non-interactive streams.""",
+            "default": None,
+            "oneOf": [{"type": "integer"},
+                      {"type": "null"}],
             "scope": "table"}
     },
     # All other keys are column names.
diff --git a/pyout/interface.py b/pyout/interface.py
index 3050cf4..805108c 100644
--- a/pyout/interface.py
+++ b/pyout/interface.py
@@ -125,7 +125,7 @@ class Writer(object):
             self.mode = "final"
 
         style = style or {}
-        if "width_" not in style and self._stream.width:
+        if style.get("width_") is None:
             lgr.debug("Setting width to stream width: %s",
                       self._stream.width)
             style["width_"] = self._stream.width


Test patch:
diff --git a/pyout/tests/test_tabular.py b/pyout/tests/test_tabular.py
index 945840b..fbb67b3 100644
--- a/pyout/tests/test_tabular.py
+++ b/pyout/tests/test_tabular.py
@@ -133,6 +133,36 @@ def test_tabular_width_no_style():
     assert out.stdout == "a" * 97 + "...\n"
 
 
+def test_tabular_width_non_interactive_default():
+    out = Tabular(["name", "status"], interactive=False)
+    a = "a" * 70
+    b = "b" * 100
+    with out:
+        out([a, b])
+    assert out.stdout == "{} {}\n".format(a, b)
+
+
+def test_tabular_width_non_interactive_width_override():
+    out = Tabular(["name", "status"],
+                  style={"width_": 31,
+                         "default_": {"width": {"marker": "…"}}},
+                  interactive=False)
+    with out:
+        out(["a" * 70, "b" * 100])
+    stdout = out.stdout
+    assert stdout == "{} {}\n".format("a" * 14 + "…", "b" * 14 + "…")
+
+
+def test_tabular_width_non_interactive_col_max():
+    out = Tabular(["name", "status"],
+                  style={"status": {"width": {"max": 20, "marker": "…"}}},
+                  interactive=False)
+    with out:
+        out(["a" * 70, "b" * 100])
+    stdout = out.stdout
+    assert stdout == "{} {}\n".format("a" * 70, "b" * 19 + "…")
+
+
 def test_tabular_write_header():
     out = Tabular(["name", "status"],
                   style={"header_": {},