skip to main content

@tonyfast s notebooks

site navigation
notebook summary
title
using tables to structure tracebacks
description
tracebacks are critical to improving code, but they must something that can be explored. this is not the case for AT the moment. exceptions are represented as long strings with no structure.
cells
24 total
13 code
state
executed in order
kernel
Python 3 (ipykernel)
language
python
name
python3
lines of code
116
outputs
6
table of contents
{"kernelspec": {"display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.3"}, "widgets": {"application/vnd.jupyter.widget-state+json": {"state": {}, "version_major": 2, "version_minor": 0}}, "title": "using tables to structure tracebacks", "description": "tracebacks are critical to improving code, but they must something that can be explored. this is not the case for AT the moment. exceptions are represented as long strings with no structure."}
notebook toolbar
Activate
cell ordering
1

using tables to structure tracebacks

tracebacks are critical to improving code, but they must something that can be explored. this is not the case for AT the moment. exceptions are represented as long strings with no structure.

this approach uses to tables to structure tracebacks with improve the quality of experience for screen readers.

2

we still need to surface the code hints provided by the new traceback module works

https://github.com/python/cpython/blob/main/Lib/traceback.py#L544

3
    import sysconfig, operator, pathlib
    import traceback, contextlib, pandas, nbconvert_a11y
    %reload_ext nbconvert_a11y.outputs
    %reload_ext nbconvert_a11y.tables
    from nbconvert_a11y import tables
2 outputs.
/tmp/ipykernel_53456/3040624387.py:2: DeprecationWarning: 
Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),
(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)
but was not found to be installed on your system.
If this would cause problems for you,
please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466
        
  import traceback, contextlib, pandas, nbconvert_a11y

4
    def multiply_wrong(x):
        "a function that wil raise an error"
        x[:-1].T@x
5

create an exception

6
    try:
        pandas.Series(range(10)).to_frame().pipe(multiply_wrong)
    except ValueError as e:
        exception = e
7
    traceback.print_exception(exception)
1 outputs.
Traceback (most recent call last):
  File "/tmp/ipykernel_53456/1648588067.py", line 2, in <module>
    pandas.Series(range(10)).to_frame().pipe(multiply_wrong)
  File "/home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/generic.py", line 6225, in pipe
    return common.pipe(self, func, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/common.py", line 500, in pipe
    return func(obj, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/ipykernel_53456/3574275760.py", line 3, in multiply_wrong
    x[:-1].T@x
    ~~~~~~~~^~
  File "/home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py", line 1775, in __matmul__
    return self.dot(other)
           ^^^^^^^^^^^^^^^
  File "/home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py", line 1725, in dot
    raise ValueError("matrices are not aligned")
ValueError: matrices are not aligned

8

turn the exceptions traceback into an array of arrays

9
    def get_exception_array(exception):
        return [
            list(frame) + [frame.colno, frame.end_colno][:0] for frame in traceback.extract_tb(exception.__traceback__)
        ]
10

format the exception as a dataframe

11
    df = pandas.DataFrame(
        get_exception_array(exception),
        columns=["file", "line", "method", "source"]
    )[["line", "method", "source", "file"]]
12

the filename makes it really hard to reason with what is being reported. it would be good to extract module name instead even though it is not part of the current repr

13

the path locations that we can use to shorten the file representation

14
    def get_paths():
        import ipykernel
        sys = sysconfig.get_paths()
        sys.update(__main__=ipykernel.compiler.get_tmp_directory())
        return sys
15
    def shorten_path(paths):
        sys = get_paths()
        visited = set()
        relative = [None]*len(paths)
        for lib in ("__main__", "purelib", "platlib", "stdlib", "platstdlib"):
            value = pathlib.Path(sys[lib])
            if value not in visited:
                for i, path in enumerate(paths):
                    if relative[i] is not None:
                        continue
                    try:
                        relative[i] = F"{lib}:{pathlib.Path(path).relative_to(value)}"
                    except ValueError:
                        pass
                
                visited.add(value)
        return relative
16

the dataframe indexes by shorted filenames making it easier to listen to

17

the traceback table is nested inside a figcaption that captures externals messages contained on the exception.

18
    pandas.DataFrame(get_exception_array(exception), columns=["file", "line", "method", "source"])
1 outputs.
rows
6
columns
4
indexes
rows
1
columns
1
index file line method source
0 /tmp/ipykernel_53456/1648588067.py 2 <module> pandas.Series(range(10)).to_frame().pipe(multiply_wrong)
1 /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/generic.py 6225 pipe return common.pipe(self, func, *args, **kwargs)
2 /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/common.py 500 pipe return func(obj, *args, **kwargs)
3 /tmp/ipykernel_53456/3574275760.py 3 multiply_wrong x[:-1].T@x
4 /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py 1775 __matmul__ return self.dot(other)
5 /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py 1725 dot raise ValueError("matrices are not aligned")
19
    def repr_traceback_frame(exception):
        df = pandas.DataFrame(get_exception_array(exception), columns=["file", "line", "method", "source"])
        df = df.set_index([pandas.Index(
            df.file.pipe(shorten_path),
            name="module"
        )])
        return df

    def repr_traceback(exception):
        figure = nbconvert_a11y.outputs.new(
            "figure", 
            tables.get_table(repr_traceback_frame(exception), type_=type(exception), COL_INDEX=tables.SHOW_INDEX.nonvisual, ROW_INDEX=tables.SHOW_INDEX.nonvisual, SEMANTIC=False),
            nbconvert_a11y.outputs.new("figcaption", F"{type(exception).__name__}: {exception}")
        )
        return str(figure)
20

an accessible figure/table for the traceback

21
    display({"text/html": repr_traceback(exception)}, raw=True)
1 outputs.
rows
6
columns
4
indexes
rows
1
columns
1
module file line method source
__main__:1648588067.py /tmp/ipykernel_53456/1648588067.py 2 <module> pandas.Series(range(10)).to_frame().pipe(multiply_wrong)
purelib:pandas/core/generic.py /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/generic.py 6225 pipe return common.pipe(self, func, *args, **kwargs)
purelib:pandas/core/common.py /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/common.py 500 pipe return func(obj, *args, **kwargs)
__main__:3574275760.py /tmp/ipykernel_53456/3574275760.py 3 multiply_wrong x[:-1].T@x
purelib:pandas/core/frame.py /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py 1775 __matmul__ return self.dot(other)
purelib:pandas/core/frame.py /home/tbone/mambaforge/envs/p311/lib/python3.11/site-packages/pandas/core/frame.py 1725 dot raise ValueError("matrices are not aligned")
ValueError: matrices are not aligned
22

custom css to make the table appear similar to native tracebacks

23
%%html
<style>
table[itemscope]::before {
    content: "Traceback (most recent call last):";
}
table[itemscope] {
    td data {color: unset;}
    tr:first-child, tr > th:first-child {
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        height: 1px;
        overflow: hidden;
        position: absolute;
        white-space: nowrap;
        width: 1px;
    }
    tr {
        display: block;
        position: relative;

        td {
            display: inline;
        }
        td:nth-of-type(1)::before {content: 'File "';}
        td:nth-of-type(1)::after {content: '", ';}
        td:nth-of-type(2)::before {content: 'line ';}
        td:nth-of-type(2)::after {content: ', ';}
        td:nth-of-type(3)::before {content: 'in ';}
        td {
            left: 2em;
            position: relative;
        }
        td:nth-of-type(4) {
            display: block;
            left: 4em;
        }
    }

}
figure {
    figcaption {
        font-family: monospace;
    }
}
</style>
1 outputs.
24