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

stack_data / tracebacks #2

Closed
alexmojaki opened this issue Aug 21, 2024 · 1 comment
Closed

stack_data / tracebacks #2

alexmojaki opened this issue Aug 21, 2024 · 1 comment

Comments

@alexmojaki
Copy link

Responding to ipython/ipython#13598 (comment)

Your extension transforms hello() into

_ttemp = hello()
if inspect.iscoroutine(_ttemp):
    _ttemp = asyncio.create_task(_ttemp)
    await _ttemp
_ttemp

When hello() raises an exception, the traceback points to line 5 (await _ttemp). But the only source code available is hello() which only has one line. stack_data is failing because it can't find the nonexistent source code. Nothing possibly could.

Worse, if the user enters an expression that actually has 5 lines, there will be no error, the traceback will just silently point at the wrong line. I can confirm this:

In [6]: hello(
   ...: 1,
   ...: 2,
   ...: 3,
   ...: 4,
   ...: 5,
   ...: 6)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
Cell In[6], line 5
      1 hello(
      2 1,
      3 2,
      4 3,
----> 5 4,
      6 5,
      7 6)

Cell In[4], line 1, in hello(*_)
----> 1 async def hello(*_): raise Exception("uh oh")

A simple fix would be to define a function maybe_await and then always transform x into await maybe_await(x). Then the traceback would always point to line 1 of the interactive cell (that can't go wrong) as well as to the body of maybe_await making the magic less invisible and mysterious:

In [7]: async def maybe_await(x):
   ...:     import asyncio
   ...:     import inspect
   ...: 
   ...:     if inspect.iscoroutine(x):
   ...:         x = asyncio.create_task(x)
   ...:         await x
   ...:     return x
   ...: 

In [8]: await maybe_await(hello(
   ...: 1,
   ...: 2))
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
Cell In[8], line 1
----> 1 await maybe_await(hello(
      2 1,
      3 2))

Cell In[7], line 7, in maybe_await(x)
      5 if inspect.iscoroutine(x):
      6     x = asyncio.create_task(x)
----> 7     await x
      8 return x

Cell In[4], line 1, in hello(*_)
----> 1 async def hello(*_): raise Exception("uh oh")

Exception: uh oh
@gsmecher
Copy link
Owner

Ah - I see. There's some amount of "no good deed goes unpunished" associated with open-source code. I should have begun with a "thanks for your work". Also, now, thanks for your time on this little project.

I had hoped ast.copy_location() would do a good job of fixing this - let me see if I can come up with something.

gsmecher pushed a commit that referenced this issue Aug 22, 2024
We splice in AST data generated by ast.parse()ing a text block.  This
AST carries its own metadata (lineno and friends) associated with the
injected code. When it's introspected in the process of generating a
traceback, it's bogus because it doesn't correspond to lines of code in
the actual ipython cell.

This patch introduces a second AST transformer that recursively copies
node metadata from the original, un-transformed AST. As a result,
traceback can point to the correct line of original code (even if it's
not what actually got executed.)
gsmecher pushed a commit that referenced this issue Aug 22, 2024
We splice in AST data generated by ast.parse()ing a text block.  This
AST carries its own metadata (lineno and friends) associated with the
injected code. When it's introspected in the process of generating a
traceback, it's bogus because it doesn't correspond to lines of code in
the actual ipython cell.

This patch introduces a second AST transformer that recursively copies
node metadata from the original, un-transformed AST. As a result,
traceback can point to the correct line of original code (even if it's
not what actually got executed.)
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

2 participants