diff --git a/graphblas/dtypes.py b/graphblas/dtypes.py index 32e3bf260..06076ccc3 100644 --- a/graphblas/dtypes.py +++ b/graphblas/dtypes.py @@ -257,7 +257,7 @@ def lookup_dtype(key, value=None): return lookup_dtype(key.literal_type) # For numba dtype inference except Exception: pass - raise ValueError(f"Unknown dtype: {key}", type(key)) + raise ValueError(f"Unknown dtype: {key} of type {type(key)}") def unify(type1, type2, *, is_left_scalar=False, is_right_scalar=False): diff --git a/graphblas/recorder.py b/graphblas/recorder.py index 610bff3cf..8f3a9b281 100644 --- a/graphblas/recorder.py +++ b/graphblas/recorder.py @@ -103,9 +103,7 @@ def __iter__(self): def is_recording(self): return self._token is not None and _recorder.get(base._prev_recorder) is self - def _repr_markdown_(self): - # Syntax highlighting from github-flavored markdown looks better than - # using IPython.display.Code or pygments + def _repr_base_(self): status = ( '
", f"{CSS_STYLE}", '
', @@ -135,27 +133,48 @@ def _repr_markdown_(self): "", "", '
', - "", - "```C", - " " + "\n ".join(self.data), - "```", - "
", - "
", - "
", ] - return "\n".join(lines) + tail = "\n\n\n" + return "\n".join(head), tail + + def _repr_html_(self): # pragma: no cover + try: + from IPython.display import Code + except ImportError: + raise NotImplementedError() + lines = self._get_repr_lines() + code = Code("\n".join(lines), language="C") + head, tail = self._repr_base_() + return head + code._repr_html_() + tail - def __repr__(self): - lines = [f'gb.Recorder ({"" if self.is_recording else "not "}recording)'] - lines.append("-" * len(lines[0])) + def _repr_markdown_(self): + # Syntax highlighting from github-flavored markdown looks better than + # using IPython.display.Code or pygments + lines = self._get_repr_lines() + code = "\n\n```C\n" + "\n".join(lines) + "\n```" + head, tail = self._repr_base_() + return head + code + tail + + def _get_repr_lines(self, indent=""): + lines = [] if self.max_rows is not None and len(self.data) > self.max_rows: - lines.extend(f" {line}" for line in self.data[: self.max_rows // 2]) + lines.extend(f"{indent}{line}" for line in self.data[: self.max_rows // 2]) lines.append("") - lines.append(f" ... ({len(self.data) - self.max_rows} rows not shown)") + lines.append( + f"{indent}// {len(self.data) - self.max_rows} rows not shown; " + # f"{indent}// {len(self.data) - self.max_rows} rows not shown; " + "set `recorder.max_rows` attribute to show more (or less)" + ) lines.append("") - lines.extend(f" {line}" for line in self.data[-((self.max_rows + 1) // 2) :]) + lines.extend(f"{indent}{line}" for line in self.data[-((self.max_rows + 1) // 2) :]) else: - lines.extend(f" {line}" for line in self.data) + lines.extend(f"{indent}{line}" for line in self.data) + return lines + + def __repr__(self): + lines = [f'gb.Recorder ({"" if self.is_recording else "not "}recording)'] + lines.append("-" * len(lines[0])) + lines.extend(self._get_repr_lines(indent=" ")) return "\n".join(lines) diff --git a/graphblas/tests/test_recorder.py b/graphblas/tests/test_recorder.py index b03b15b7f..aa0a54575 100644 --- a/graphblas/tests/test_recorder.py +++ b/graphblas/tests/test_recorder.py @@ -111,6 +111,7 @@ def test_record_repr(switch): rec.max_rows = 10 for i in range(1, 20): A[0, 0].new(name=f"c{i}") + n = len(rec.data) - rec.max_rows if switch: assert repr(rec) == ( "gb.Recorder (recording)\n" @@ -121,7 +122,7 @@ def test_record_repr(switch): " GrB_Matrix_extractElement_INT64(&c3, A, 0, 0);\n" " GrB_Matrix_extractElement_INT64(&c4, A, 0, 0);\n" "\n" - " ... (10 rows not shown)\n" + f" // {n} rows not shown; set `recorder.max_rows` attribute to show more (or less)\n" "\n" " GrB_Matrix_extractElement_INT64(&c15, A, 0, 0);\n" " GrB_Matrix_extractElement_INT64(&c16, A, 0, 0);\n" @@ -139,7 +140,7 @@ def test_record_repr(switch): " GrB_Matrix_extractElement_Scalar(c1, A, 0, 0);\n" " GrB_Scalar_new(&c2, GrB_INT64);\n" "\n" - " ... (30 rows not shown)\n" + f" // {n} rows not shown; set `recorder.max_rows` attribute to show more (or less)\n" "\n" " GrB_Matrix_extractElement_Scalar(c17, A, 0, 0);\n" " GrB_Scalar_new(&c18, GrB_INT64);\n" @@ -156,11 +157,9 @@ def test_record_repr_markdown(switch): rec.start() A[0, 0].new(name="c") if switch: - text = " GrB_Matrix_extractElement_INT64(&c, A, 0, 0);\n" + text = "GrB_Matrix_extractElement_INT64(&c, A, 0, 0);\n" else: - text = ( - " GrB_Scalar_new(&c, GrB_INT64);\n" " GrB_Matrix_extractElement_Scalar(c, A, 0, 0);\n" - ) + text = "GrB_Scalar_new(&c, GrB_INT64);\nGrB_Matrix_extractElement_Scalar(c, A, 0, 0);\n" assert rec._repr_markdown_() == ( "
\n" f"{CSS_STYLE}\n" @@ -185,11 +184,9 @@ def test_record_repr_markdown(switch): ) rec.stop() if switch: - text = " GrB_Matrix_extractElement_INT64(&c, A, 0, 0);\n" + text = "GrB_Matrix_extractElement_INT64(&c, A, 0, 0);\n" else: - text = ( - " GrB_Scalar_new(&c, GrB_INT64);\n" " GrB_Matrix_extractElement_Scalar(c, A, 0, 0);\n" - ) + text = "GrB_Scalar_new(&c, GrB_INT64);\nGrB_Matrix_extractElement_Scalar(c, A, 0, 0);\n" assert rec._repr_markdown_() == ( "
\n" f"{CSS_STYLE}\n" @@ -214,6 +211,20 @@ def test_record_repr_markdown(switch): ) +def test_record_repr_html(switch): + A = gb.Matrix(int, 3, 3, name="A") + rec = gb.Recorder() + rec.start() + A[0, 0].new(name="c") + try: + import IPython # noqa + except ImportError: + with pytest.raises(NotImplementedError): + rec._repr_html_() + else: # pragma: no cover + assert isinstance(rec._repr_html_(), str) + + def test_record_failed_call(): BIG = gb.Vector(int, size=2**55) small = gb.Vector(int, size=2**55)