microsoft / PTVS

Python Tools for Visual Studio
https://aka.ms/PTVS
Apache License 2.0
2.53k stars 676 forks source link

User-unhandled exceptions don't work properly in remote debugging #789

Closed qtiki closed 3 years ago

qtiki commented 9 years ago

User-unhandled exceptions work properly for this code when ran with "Start Debugging" from within Visual Studio:

try:
  x()
except NameError:
  pass

x() # debugger catches this one

However when ran with remote debugging it only works when the python process is started with the same absolute path of the script file. Using a relative path for the Python script does not work, which means it is not possible to catch user-unhandled exceptions properly when remote debugging Python running on a Linux machine for example.

Here's what I used to test this:

import ptvsd
ptvsd.enable_attach(secret = None)
ptvsd.wait_for_attach()

try:
  x() # debugger will break here when remote debugging with relative path on localhost or any path on remote Linux machine
except NameError:
  pass

x() # debugger will break here when remote debugging with the same absolute path on localhost

I was able to reproduce this problem with Visual Studio 2012 + PTVS 2.1 and also with Visual Studio 2015 + PTVS 2.2.

int19h commented 9 years ago

This is the consequence of us doing handled exception detection by looking at the AST, and performing that on the VS side of things - so if it doesn't find the file to parse, it has to assume that the exception is unhandled.

Note that this is unlike breakpoint filename matching, because in that case we already have both the remote path and the local path, and just need to compare them properly to get a fuzzy match. But here we only have the remote file name from the debuggee, with no clue as to how to map it to a local one.

Once we do #658, we should make sure that we use the downloaded sources for this, rather than local files.

qtiki commented 9 years ago

I sort of suspected that there might be something like this going on. Can you think of any possible workarounds for this until a real solution is implemented (I'm assuming it might take a while)? It would be "very nice" for our use case; we use a custom Visual Studio add-in to copy the Python files over to a remote Linux server via ssh where they are then then ran inside embedded Python. So we always have the local files and remote files in sync - PTVS just can't connect the dots.

I have to say that PTVS has been a huge boost to our development environment compared to editing code with VI and reading through logs to see what's happening. Having user-unhandled exceptions work properly would really be the icing on the cake.

int19h commented 9 years ago

I can't think of any proper workaround here - it's just something that needs to be done right. The best you can do right now, unfortunately, is disable notifications for user-unhandled exceptions of that type in Debug -> Exceptions (but then of course you won't see the debugger stop if it's actually user-unhandled - it'll be printed to Output, and then the process will terminate).

As a one-off thing, you could try hacking on ptvsd source code (which is pure Python) to add your own filename mappings. This is the line of code which sends the filename to VS for exception handling purposes - if you change it here to be what VS can find on its side, then it should work:

https://github.com/Microsoft/PTVS/blob/master/Python/Product/PythonTools/visualstudio_py_debugger.py#L492

qtiki commented 9 years ago

Thank you very much for pointing me into the right direction for a "one-off hack". Saved me a lot of time.

In case someone else runs into the same issue here's what I used for a temporary workaround. I added a filename mapping function to the visualstudio_py_debugger.py file which I then call in the place int19h pointed me to:

def map_remote_filename_hack(filename):
    if 'PTVSD_DEBUGGER_PYTHONPATH' in environ:
        import ntpath
        return ntpath.normpath(environ['PTVSD_DEBUGGER_PYTHONPATH'] +
          filename[len(path.commonprefix((environ['PYTHONPATH'], filename))):])
    else:
        return filename

Since we were already using PYTHONPATH environment variable it made sense to add another one for this hack so the program we're running embedded Python from didn't need any modifications.

ps. I understand this is an awful hack and I won't be making any pull requests based on this... :)

zooba commented 9 years ago

It might be better (or at least interesting) to do this on the Python side rather than the VS side, and we may even be able to achieve something similar by looking at bytecode.

Could also be done by sending source files back to VS, which is also on the list of things to consider.