prettyprinter icon indicating copy to clipboard operation
prettyprinter copied to clipboard

Improve prettyprinting of multidimensional numpy arrays.

Open anntzer opened this issue 6 years ago • 1 comments

Items are now aligned by relying on numpy's own implementation.

Fixes most of #49.

It looks like I needed to insert hard linebreaks myself to get the right indentation. One minor remaining problematic point is that the array's dtype gets printed on the same line as the array (if it fits) rather than on a separate line:

In [1]: np.arange(4, dtype=np.uint8).reshape((2, 2))                                                                 
Out[1]: 
numpy.ndarray(
    [[0, 1],
     [2, 3]], dtype='uint8')  # dtype='uint8' should go to the next line...

I guess the proper fix would be to move the dtype-handling logic from pretty_numpy to pretty_arraywrapper as well, but this would also require (I think?) duplicating some of the pretty_call logic, so it won't be for this PR...

anntzer avatar Mar 26 '19 14:03 anntzer

After some more investigation, looks like the desired result (forcing a newline before the dtype if the array repr goes over multiple lines) can be achieved with

diff --git i/prettyprinter/extras/numpy.py w/prettyprinter/extras/numpy.py
index e9aa1f6..7dffb34 100644
--- i/prettyprinter/extras/numpy.py
+++ w/prettyprinter/extras/numpy.py
@@ -47,8 +47,8 @@ def pretty_arraywrapper(value, ctx):
     if len(lines) == 1:
         return s
     else:
-        interspersed = [HARDLINE] * 2 * len(lines)
-        interspersed[1::2] = lines
+        interspersed = [HARDLINE] * (2 * len(lines) - 1)
+        interspersed[::2] = lines
         return Concat(interspersed)
 
 
diff --git i/prettyprinter/prettyprinter.py w/prettyprinter/prettyprinter.py
index 521ad01..e249284 100644
--- i/prettyprinter/prettyprinter.py
+++ w/prettyprinter/prettyprinter.py
@@ -893,6 +893,7 @@ def build_fncall(
         fndoc = general_identifier(fndoc)
 
     has_comment = bool(trailing_comment)
+    has_hardline = False
 
     argdocs = list(argdocs)
     kwargdocs = list(kwargdocs)
@@ -957,6 +958,10 @@ def build_fncall(
         else:
             comment_str = None
 
+        from .doctypes import Concat, HARDLINE
+        if isinstance(doc, Concat) and any(doc is HARDLINE for doc in doc.docs):
+            has_hardline = True
+
         part = concat([doc, NIL if last else COMMA])
 
         if comment_str:
@@ -982,7 +987,7 @@ def build_fncall(
 
     outer = (
         always_break
-        if has_comment
+        if has_comment or has_hardline
         else group
     )

(on top of this PR's patch).

I guess always breaking when a subdoc has hardlines makes sense? Not sure about possible unintended consequences, though.

anntzer avatar Mar 26 '19 23:03 anntzer