Repository: python-graphblas/python-graphblas

Issue:
Format still shown in expression reprs
In https://github.com/python-graphblas/python-graphblas/pull/282, `_html_repr_` for expressions was updated to exclude the `format` field. The `__repr__` still shows the format.  `__repr__` should probably be updated to not show the format.

Here is current behavior:
```python
In [1]: import graphblas as gb

In [2]: A = gb.Matrix(int, 2, 2)

In [3]: A << 1

In [4]: A + 1
Out[4]:
gb.MatrixExpression                     nrows  ncols  dtype
M_0.apply(binary.plus[INT64], right=1)      2      2  INT64

"Result"   nvals  nrows  ncols  dtype       format
gb.Matrix      4      2      2  INT64  fullr (iso)
--------------------------------------------------
   0  1
0  2  2
1  2  2

Do expr.new() or other << expr to calculate the expression.
```

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/53521262/badge)](https://coveralls.io/builds/53521262)

Coverage increased (+0.0002%) to 98.676% when pulling **dbb784db822bfc5f68b04da99cae95fdbfd38c15 on eriknw:no_format_expr_repr** into **d0c41f20cb75ade48d1676803b9d56357851681f on python-graphblas:main**.


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 52d3b37..d5df8fb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -16,7 +16,7 @@ repos:
       - id: mixed-line-ending
       - id: trailing-whitespace
   - repo: https://github.com/myint/autoflake
-    rev: v1.7.6
+    rev: v1.7.7
     hooks:
       - id: autoflake
         args: [--in-place]
@@ -54,7 +54,7 @@ repos:
       - id: yesqa
         additional_dependencies: *flake8_dependencies
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.2.0
+    rev: v2.2.2
     hooks:
       - id: codespell
         types_or: [python, rst, markdown]
diff --git a/graphblas/core/formatting.py b/graphblas/core/formatting.py
index 9c3dfbe..ffe7635 100644
--- a/graphblas/core/formatting.py
+++ b/graphblas/core/formatting.py
@@ -355,7 +355,7 @@ def get_format(x, is_transposed=False):
     return fmt
 
 
-def matrix_info(matrix, *, mask=None, for_html=True):
+def matrix_info(matrix, *, mask=None, expr=None, for_html=True):
     if mask is not None:
         if for_html:
             name = f"{type(mask).__name__}\nof\ngb.{type(matrix).__name__}"
@@ -363,16 +363,18 @@ def matrix_info(matrix, *, mask=None, for_html=True):
             name = [f"{type(mask).__name__}", f"of gb.{type(matrix).__name__}"]
     else:
         name = f"gb.{type(matrix).__name__}"
-    keys = ["nvals", "nrows", "ncols", "dtype", "format"]
+    keys = ["nvals", "nrows", "ncols", "dtype"]
     vals = [matrix._nvals, matrix._nrows, matrix._ncols, matrix.dtype.name]
-    if type(matrix) is Matrix:
-        vals.append(get_format(matrix))
-    else:  # TransposedMatrix
-        vals.append(get_format(matrix._matrix, is_transposed=True))
+    if expr is None:
+        keys.append("format")
+        if type(matrix) is Matrix:
+            vals.append(get_format(matrix))
+        else:  # TransposedMatrix
+            vals.append(get_format(matrix._matrix, is_transposed=True))
     return name, keys, vals
 
 
-def vector_info(vector, *, mask=None, for_html=True):
+def vector_info(vector, *, mask=None, expr=None, for_html=True):
     if mask is not None:
         if for_html:
             name = f"{type(mask).__name__}\nof\ngb.{type(vector).__name__}"
@@ -381,8 +383,11 @@ def vector_info(vector, *, mask=None, for_html=True):
     else:
         name = f"gb.{type(vector).__name__}"
     # SS, SuiteSparse-specific: format
-    keys = ["nvals", "size", "dtype", "format"]
-    vals = [vector._nvals, vector._size, vector.dtype.name, get_format(vector)]
+    keys = ["nvals", "size", "dtype"]
+    vals = [vector._nvals, vector._size, vector.dtype.name]
+    if expr is None:
+        keys.append("format")
+        vals.append(get_format(vector))
     return name, keys, vals
 
 
@@ -405,12 +410,8 @@ def matrix_header_html(matrix, *, mask=None):
 
 
 def matrix_expression_header_html(matrix, expr):
-    _, keys, vals = matrix_info(matrix, for_html=True)
+    _, keys, vals = matrix_info(matrix, expr=expr, for_html=True)
     name = expr._format_expr_html()
-    # Drop format (the last entry)
-    assert keys[-1] == "format"
-    keys = keys[:-1]
-    vals = vals[:-1]
     return create_header_html(name, keys, vals)
 
 
@@ -420,12 +421,8 @@ def vector_header_html(vector, *, mask=None):
 
 
 def vector_expression_header_html(matrix, expr):
-    _, keys, vals = vector_info(matrix, for_html=True)
+    _, keys, vals = vector_info(matrix, expr=expr, for_html=True)
     name = expr._format_expr_html()
-    # Drop format (the last entry)
-    assert keys[-1] == "format"
-    keys = keys[:-1]
-    vals = vals[:-1]
     return create_header_html(name, keys, vals)
 
 
@@ -497,7 +494,7 @@ def format_scalar_html(scalar, expr=None):
     return f'{CSS_STYLE}<div class="gb-scalar"><tt>{top_name}</tt>{header}</div>'
 
 
-def format_scalar(scalar):
+def format_scalar(scalar, expr=None):
     return create_header(
         "gb.Scalar",
         ["value", "dtype"],
@@ -519,7 +516,7 @@ def get_expr_result(expr, html=False):
         if html:
             arg_string = f"{val._repr_html_(expr=expr)}"
         else:
-            arg_string = f"{val}"
+            arg_string = val.__repr__(expr=expr)
         val.name = name
     return arg_string
 
@@ -654,8 +651,8 @@ def create_header(type_name, keys, vals, *, lower_border=False, name="", quote=T
     return "\n".join(lines)
 
 
-def format_matrix(matrix, *, max_rows=None, min_rows=None, max_columns=None, mask=None):
-    name, keys, vals = matrix_info(matrix, mask=mask, for_html=False)
+def format_matrix(matrix, *, max_rows=None, min_rows=None, max_columns=None, mask=None, expr=None):
+    name, keys, vals = matrix_info(matrix, mask=mask, expr=expr, for_html=False)
     header = create_header(
         name,
         keys,
@@ -674,8 +671,8 @@ def format_matrix(matrix, *, max_rows=None, min_rows=None, max_columns=None, mas
     return header
 
 
-def format_vector(vector, *, max_rows=None, min_rows=None, max_columns=None, mask=None):
-    name, keys, vals = vector_info(vector, mask=mask, for_html=False)
+def format_vector(vector, *, max_rows=None, min_rows=None, max_columns=None, mask=None, expr=None):
+    name, keys, vals = vector_info(vector, mask=mask, expr=expr, for_html=False)
     header = create_header(
         name,
         keys,
diff --git a/graphblas/core/matrix.py b/graphblas/core/matrix.py
index b4dbf90..36764ce 100644
--- a/graphblas/core/matrix.py
+++ b/graphblas/core/matrix.py
@@ -123,12 +123,12 @@ class Matrix(BaseType):
             # it's difficult/dangerous to record the call, b/c `self.name` may not exist
             check_status(lib.GrB_Matrix_free(gb_obj), self)
 
-    def __repr__(self, mask=None):
+    def __repr__(self, mask=None, expr=None):
         from .formatting import format_matrix
         from .recorder import skip_record
 
         with skip_record:
-            return format_matrix(self, mask=mask)
+            return format_matrix(self, mask=mask, expr=expr)
 
     def _repr_html_(self, mask=None, collapse=False, expr=None):
         if self._parent is not None:
diff --git a/graphblas/core/scalar.py b/graphblas/core/scalar.py
index 024ceb9..ab08a35 100644
--- a/graphblas/core/scalar.py
+++ b/graphblas/core/scalar.py
@@ -103,10 +103,10 @@ class Scalar(BaseType):
         """The name used in the text for expressions in HTML formatting"""
         return self._name_html or repr(self.value)
 
-    def __repr__(self):
+    def __repr__(self, expr=None):
         from .formatting import format_scalar
 
-        return format_scalar(self)
+        return format_scalar(self, expr=expr)
 
     def _repr_html_(self, collapse=False, expr=None):
         from .formatting import format_scalar_html
diff --git a/graphblas/core/vector.py b/graphblas/core/vector.py
index 79494bd..da60153 100644
--- a/graphblas/core/vector.py
+++ b/graphblas/core/vector.py
@@ -138,12 +138,12 @@ class Vector(BaseType):
             name=f"(GrB_Matrix){self.name}",
         )
 
-    def __repr__(self, mask=None):
+    def __repr__(self, mask=None, expr=None):
         from .formatting import format_vector
         from .recorder import skip_record
 
         with skip_record:
-            return format_vector(self, mask=mask)
+            return format_vector(self, mask=mask, expr=expr)
 
     def _repr_html_(self, mask=None, collapse=False, expr=None):
         if self._parent is not None and mask is None:


Test patch:
diff --git a/graphblas/tests/test_formatting.py b/graphblas/tests/test_formatting.py
index c6a4ab9..8024644 100644
--- a/graphblas/tests/test_formatting.py
+++ b/graphblas/tests/test_formatting.py
@@ -4076,9 +4076,9 @@ def test_autocompute(A, B, v):
         "gb.MatrixExpression                        nrows  ncols  dtype\n"
         "A_1.ewise_add(A_1, op=monoid.plus[INT64])      1      5  INT64\n"
         "\n"
-        '"Result"   nvals  nrows  ncols  dtype   format\n'
-        "gb.Matrix      3      1      5  INT64  bitmapr\n"
-        "----------------------------------------------\n"
+        '"Result"   nvals  nrows  ncols  dtype\n'
+        "gb.Matrix      3      1      5  INT64\n"
+        "-------------------------------------\n"
         "   0 1  2 3  4\n"
         "0  0    2    4\n"
         "\n"
@@ -4094,9 +4094,9 @@ def test_autocompute(A, B, v):
         "gb.VectorExpression                                       size  dtype\n"
         "v_0.ewise_mult(v_1, op=binary.times[INT64])  36028797018963968  INT64\n"
         "\n"
-        '"Result"   nvals               size  dtype        format\n'
-        "gb.Vector      1  36028797018963968  INT64  sparse (iso)\n"
-        "--------------------------------------------------------\n"
+        '"Result"   nvals               size  dtype\n'
+        "gb.Vector      1  36028797018963968  INT64\n"
+        "------------------------------------------\n"
         "index 0                 1                  ... 36028797018963966 36028797018963967\n"
         "value                 2                    ...                                    \n"
         "\n"
@@ -4130,9 +4130,9 @@ def test_autocompute(A, B, v):
         "gb.MatrixEwiseMultExpr  nrows  ncols  left_dtype  right_dtype\n"
         "M_2 & M_2                   1      5        BOOL         BOOL\n"
         "\n"
-        '"Result"   nvals  nrows  ncols  dtype   format\n'
-        "gb.Matrix      3      1      5   BOOL  bitmapr\n"
-        "----------------------------------------------\n"
+        '"Result"   nvals  nrows  ncols  dtype\n'
+        "gb.Matrix      3      1      5   BOOL\n"
+        "-------------------------------------\n"
         "       0 1     2 3     4\n"
         "0  False    True    True\n"
         "\n"