Repository: regionmask/regionmask

Issue:
repr not correctly truncated
The repr may not correctly enforce the colwidth. It uses `maybe_truncate`. However, this only works correctly for `maxlen > 3` and this can even become negative:

https://github.com/regionmask/regionmask/blob/60a5fe14cfd03e97e255c0580a142e1982421969/regionmask/core/formatting.py#L35

```python
import regionmask
print(regionmask.core.formatting.maybe_truncate("A short text", 0))
print(regionmask.core.formatting.maybe_truncate("A short text", 2))
print(regionmask.core.formatting.maybe_truncate("A short text", 3))
print(regionmask.core.formatting.maybe_truncate("A short text", 4))
```

I am also not sure if `df.to_string(..., line_width=max_width)` does the right thing.




Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/regionmask/regionmask/pull/378?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) Report
> Merging [#378](https://codecov.io/gh/regionmask/regionmask/pull/378?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (2223cdd) into [main](https://codecov.io/gh/regionmask/regionmask/commit/60a5fe14cfd03e97e255c0580a142e1982421969?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (60a5fe1) will **decrease** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main     #378      +/-   ##
==========================================
- Coverage   98.62%   98.62%   -0.01%     
==========================================
  Files          16       16              
  Lines        1386     1385       -1     
==========================================
- Hits         1367     1366       -1     
  Misses         19       19              
```

| Flag | Coverage Δ | |
|---|---|---|
| bare-minimum | `91.69% <100.00%> (-0.01%)` | :arrow_down: |
| min-all-deps | `97.84% <100.00%> (-0.01%)` | :arrow_down: |
| unittests | `98.62% <100.00%> (-0.01%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/regionmask/regionmask/pull/378?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | Coverage Δ | |
|---|---|---|
| [regionmask/core/formatting.py](https://codecov.io/gh/regionmask/regionmask/pull/378/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9jb3JlL2Zvcm1hdHRpbmcucHk=) | `96.87% <100.00%> (-0.10%)` | :arrow_down: |
| [regionmask/core/regions.py](https://codecov.io/gh/regionmask/regionmask/pull/378/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9jb3JlL3JlZ2lvbnMucHk=) | `97.53% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask)


Patch:
diff --git a/docs/whats_new.rst b/docs/whats_new.rst
index 5a4c3b7..2511f55 100644
--- a/docs/whats_new.rst
+++ b/docs/whats_new.rst
@@ -60,6 +60,7 @@ Internal Changes
   - in the function to determine points at *exactly* -180°E (or 0°E) and -90°N (:pull:`341`)
 - Use importlib.metadata if available (i.e. for python > 3.7) - should lead to a faster
   import time for regionmask (:pull:`369`).
+- Small changes to the repr of :py:class:`Regions`  (:pull:`378`).
 
 .. _whats-new.0.9.0:
 
diff --git a/regionmask/core/formatting.py b/regionmask/core/formatting.py
index f14c314..332e916 100644
--- a/regionmask/core/formatting.py
+++ b/regionmask/core/formatting.py
@@ -1,51 +1,33 @@
 """String formatting routines for __repr__."""
 
-
 from pandas.io.formats import console
 
 
-def pretty_print(x, numchars, right=True):
-    """Given an object `x`, call `str(x)` and format the returned string so
-    that it is numchars long, padding with trailing spaces or truncating with
-    ellipses as necessary
-    """
-
-    # copied from xarray
-
-    s = maybe_truncate(x, numchars)
-    if right:
-        return s + " " * max(numchars - len(s), 0)
-
-    return " " * max(numchars - len(s), 0) + s
-
-
 def maybe_truncate(obj, maxlen=500):
 
     # copied from xarray
 
     s = str(obj)
     if len(s) > maxlen:
-        s = s[: (maxlen - 3)] + "..."
+        s = s[: max(maxlen - 3, 0)] + "..."
     return s
 
 
-def _display_metadata(name, source, overlap, max_width=80):
-    pad = 10
+def _display_metadata(source, overlap, max_width=80):
 
-    name = pretty_print("Name:", pad) + maybe_truncate(name, max_width - pad)
-    summary = [name]
+    summary = []
 
     if source is not None:
-        source = pretty_print("Source:", pad) + maybe_truncate(source, max_width - pad)
+        source = maybe_truncate(f"Source:   {source}", max_width)
         summary.append(source)
 
-    overlap = pretty_print("overlap:", pad) + f"{overlap}"
+    overlap = f"overlap:  {overlap}"
     summary.append(overlap)
 
     return summary
 
 
-def _display_regions_gp(self, max_rows, max_width, max_colwidth):  # pragma: no cover
+def _display_regions_gp(self, max_rows, max_width):
     summary = ["Regions:"]
 
     # __repr__ of polygons can be slow -> use pd.DataFrame
@@ -67,21 +49,20 @@ def _display_regions_gp(self, max_rows, max_width, max_colwidth):  # pragma: no
     return summary
 
 
-def _display(self, max_rows=10, max_width=None, max_colwidth=50):
+def _display(self, max_rows=10, max_width=None):
 
-    summary = [f"<regionmask.{type(self).__name__}>"]
+    if max_width is None:
+        max_width, _ = console.get_console_size()
+
+    title = f"<regionmask.{type(self).__name__} '{self.name}'>"
+    summary = [maybe_truncate(title, max_width)]
 
     if max_rows is None:
         max_rows = len(self)
 
-    if max_width is None:
-        max_width, _ = console.get_console_size()
-
-    summary += _display_metadata(
-        self.name, self.source, self.overlap, max_width=max_width
-    )
+    summary += _display_metadata(self.source, self.overlap, max_width=max_width)
     summary.append("")
-    summary += _display_regions_gp(self, max_rows, max_width, max_colwidth)
+    summary += _display_regions_gp(self, max_rows, max_width)
 
     summary.append("")
     summary.append(f"[{len(self):d} regions]")
diff --git a/regionmask/core/regions.py b/regionmask/core/regions.py
index cf4d03f..71654c1 100644
--- a/regionmask/core/regions.py
+++ b/regionmask/core/regions.py
@@ -284,7 +284,7 @@ class Regions:
         Used as the repr.
 
         """
-        return _display(self, max_rows, max_width, max_colwidth)
+        return _display(self, max_rows, max_width)
 
     @_deprecate_positional_args("0.10.0")
     def mask(


Test patch:
diff --git a/regionmask/tests/test_formatting.py b/regionmask/tests/test_formatting.py
index 8d368f8..b7a3127 100644
--- a/regionmask/tests/test_formatting.py
+++ b/regionmask/tests/test_formatting.py
@@ -4,17 +4,13 @@ from regionmask.core import formatting
 from regionmask.defined_regions import srex
 
 
-def test_pretty_print():
-    assert formatting.pretty_print("abcdefghij", 8) == "abcde..."
-    assert formatting.pretty_print("ß", 1) == "ß"
-    assert formatting.pretty_print("x", 3) == "x  "
-    assert formatting.pretty_print("x", 3, False) == "  x"
-
-
 def test_maybe_truncate():
     assert formatting.maybe_truncate("ß", 10) == "ß"
     assert formatting.maybe_truncate("abcdefghij", 8) == "abcde..."
 
+    for max_length in range(-1, 4):
+        assert formatting.maybe_truncate("abcdefghij", max_length) == "..."
+
 
 def test_repr_srex():
 
@@ -22,8 +18,7 @@ def test_repr_srex():
 
     result = srex.__repr__()
 
-    expected = """<regionmask.Regions>
-Name:     SREX
+    expected = """<regionmask.Regions 'SREX'>
 Source:   Seneviratne et al., 2012 (https://www.ipcc.ch/site/assets/uploads/2...
 overlap:  False
 
@@ -47,14 +42,14 @@ Regions:
 
 def test_display_metadata():
 
-    expected = ["Name:     name", "overlap:  False"]
-    result = formatting._display_metadata("name", None, False)
+    expected = ["overlap:  False"]
+    result = formatting._display_metadata(None, False)
     assert result == expected
 
-    expected = ["Name:     name", "Source:   source", "overlap:  True"]
-    result = formatting._display_metadata("name", "source", True)
+    expected = ["Source:   source", "overlap:  True"]
+    result = formatting._display_metadata("source", True)
     assert result == expected
 
-    expected = ["Name:     na...", "overlap:  None"]
-    result = formatting._display_metadata("name of regions", None, None, max_width=15)
+    expected = ["Source:   to...", "overlap:  None"]
+    result = formatting._display_metadata("to truncate", None, max_width=15)
     assert result == expected