Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid caret position when reconstructing traceback #76

Open
achille-roussel opened this issue Feb 19, 2024 · 0 comments
Open

Invalid caret position when reconstructing traceback #76

achille-roussel opened this issue Feb 19, 2024 · 0 comments

Comments

@achille-roussel
Copy link

Hello!

Thanks for maintaining this library, it's been very useful.

I'm opening this issue to discuss an improvement that could create a better experience for developers when they are shown a stack trace for an exception that was reconstructed with tblib.Traceback.form_string(s).as_traceback().

In most cases, Python is able to show a caret below the expression that triggered the exception (e.g., as a sequence of ^).

The Python traceback package creates a FrameSummary containing colno and end_colno to track the position of the caret.

However, the dynamic traceback reconstruction that is done by tblib via compilation of code snippets results in a caret that is always ``:

  • The length corresponds to the length of the __traceback_maker type.
  • The column offset is somehow always interpreted as zero. That I haven't figured out why yet, I would expect it to be 6 since the full line triggering the exception is raise __traceback_maker.

There may be a relationship to #75 as well, since it is my understanding that the column offsets are derived from the instruction position in Python 3.11+.

def _walk_tb_with_full_positions(tb):
    # Internal version of walk_tb that yields full code positions including
    # end line and column information.
    while tb is not None:
        positions = _get_code_position(tb.tb_frame.f_code, tb.tb_lasti)
        # Yield tb_lineno when co_positions does not have a line number to
        # maintain behavior with walk_tb.
        if positions[0] is None:
            yield tb.tb_frame, (tb.tb_lineno, ) + positions[1:]
        else:
            yield tb.tb_frame, positions
        tb = tb.tb_next


def _get_code_position(code, instruction_index):
    if instruction_index < 0:
        return (None, None, None, None)
    positions_gen = code.co_positions()
    return next(itertools.islice(positions_gen, instruction_index // 2, None))

I attempted a fix in master...achille-roussel:python-tblib:fix-traceback-caret-position, but without much success, the column offsets get lost after reconstructing the traceback.

This seems like it would be worthy of more discussion before investing further, let me know what you think about the issue!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant