Remote Debugging

From The Foundry MODO SDK wiki
Jump to: navigation, search

In 701 we now have what are essentially two distinct 'paths', or 'modes' of execution for python scripts. We have the old, pre-701 style scripts that are executed using the '@' syntax or the 'script.run' command which run, as they have always done, through the command service and are transient, or, 'fire & forget'. Now, new to 701 we have python 'plugins' which register themselves into the system at start up and stay resident throughout the session, just like any regular plugin written with the SDK. The code for these new 'plugins' only executes when the functionality it defines is accessed or triggered by a user action such as a file save, for example. The differences in the way that these two routes operate means that there are some slight differences in the way that each one needs to be set up for debugging and/or the debug process itself. For the purposes of the following discussion the term 'script' or 'python script' will refer to the old style scripts executed using the '@' syntax or 'script.run' and the the term 'plugin', or 'python plugin', will refer to the new style, persistent python scripts that register themselves as servers at start up.

Not all remote debuggers appear to work well, if at all with modo. Here's a short, not exhaustive list of tested graphical debuggers/IDEs:

  1. Winpdb - working
  2. ActiveState Komodo IDE - working
  3. Wingware Wing IDE Personal - not working
  4. Wingware Wing IDE Professional - working
  5. Eric4 - not working
  6. JetBrains PyCharm - not working


WinPDB

Despite it's name WinPDB is a cross platform graphical and console debugger. It uses the wxPython runtime to generate it's UI so you will need that and a system (platform if you're on OSX) distribution of Python. It's available from the Winpdb website where you'll also find a link to the wxPython runtime files. Follow the instructions on the Winpdb site for installation. For debugging in modo it doesn't actually matter whether you install via setup.py or run as a standalone script, it works the same either way.

Setting up for use in modo

1) Copy the file 'rpdb2.py' from Winpdb'd installation folder to a location on modo's python path, ie to any valid imported folder, user:Scripts would be an obvious choice

2) Add an import directive to the top of the script to be debugged, importing 'rpdb2'

3) Add a line below the import to start the debugging engine:

rpdb2.start_embedded_debugger(password)

where 'password' is a plain text string of your choice. When it comes time to run the script and attach the debugger you will need to enter the same password into Winpdb's UI. More thorough coverage for this topic is available on the Winpdb website but one word of caution, do not use the interactive password command in your modo script, it will lock up modo requiring a force-quit.


Debugging a Python Script

Successfully debugging a python script relies quite heavily on the way the script is set up. For this demonstration I'm going to be using the following:

#!/usr/bin/env python
 
import lx
import traceback
import rpdb2
 
def start_debugger():
    rpdb2.start_embedded_debugger('mododebug')
 
def main():
    numitems = lx.eval('query sceneservice item.N ?')
    for x in range(numitems):
        id = lx.eval('query sceneservice item.id ? %s' % x)
        name = lx.eval('query sceneservice item.name ? %s' % id)
        type = lx.eval('query sceneservice item.type ? %s' % id)
        lx.out((id, name, type))
 
 
if __name__ == '__main__':
    try:
        main()
    except:
        lx.out(traceback.format_exc())


The items to note here are that the Winpdb module (rpdb2) is imported at the top, the command to start the debugger service has been enclosed in a function call, 'start_debugger()', the main body of the script is also enclosed in a function call, 'main()' and we have the common python idiom to conditionally execute the main function depending on whether the script was imported or run directly. Why structure the script like this? Well when modo executes a script through the command system it reads the file from disk and passes it as one large string buffer to the python interpreter. Unfortunately, that means that Winpdb is unable to access the raw code and single stepping through the script is impossible. Wrapping the script in this way and importing it as a module allows Winpdb to query the physical location of the file on disk. Plus, as will become apparent, it affords some flexibility during the debugging process, instead of running the script directly, using the '@' syntax or 'script.run', we can take advantage of the new persistent and interactive interpreter in 701.

For a complete walk-through of remote debugging a python script with Winpdb watch the following video - note, you can watch the video full screen by left clicking the grey rectangle at the far right end of the video control bar.



Debugging a Python plugin

For this demonstration I'll be using this plugin (it's an early version an the STL exporter).

Just as with the script debugging example we need to import the debug module (rpdb2) and wrap the command to start the debug server in a function call. This time, though, the reason is slightly different. If you study the example plugin file linked you should notice that there is no real 'body', it's just a collection of classes with a couple of calls to a function called lx.bless(). The 'bless()' function is responsible for registering the classes as servers within modo. Generally you're probably not going to want to have the debugger break in when the classes are being registered, moving the 'rpdb2.start_embedded_debugger()' command into a function body stops it being called when the plugin is first imported. If you do want to have the debugger break in during the 'blessing' stage then it's a simple matter to add a call to 'start_debugger()' just after the function definition.

#!/usr/bin/env python
 
import lx
import traceback
import rpdb2
 
def start_debugger():
    rpdb2.start_embedded_debugger('mododebug')


For a walk-through of remote debugging a python plugin with Winpdb watch the following video - as before, you can watch the video full screen by left clicking the grey rectangle at the far right end of the video control bar.



Wingware Wing IDE (professional & Personal)

Remote dubugging of both python scripts and python plugins has been confirmed to work with Wing IDE Professional and Wing IDE personal.

Setting up for use in modo

Setting up is fairly straight forward, first the Wing IDE debug client module needs copying to a location on modo's Python path, ie to any valid imported folder such as 'user:Scripts'. The client module file (wingdbstub.py) can be found in the root of the Wing IDE application folder. You'll also need to copy the 'wingdebugpw' file from your Wing IDE user settings folder to the same location as 'wingdbstub.py'. You should be able to find your Wing IDE user settings folder in 'C:\Users\username\AppData\Roaming' on Windows, it will be called either 'Wing IDE 4' or 'Wing Personal 4' depending on which version you have installed.

Open 'wingdbstub.py' in a text editor and change 'kEmbedded = 0' to 'kEmbedded = 1'

Then, at the top of the script or plugin to be debugged, below any imports, add the following lines:

def debugger():
    import wingdbstub



That's all that is really required. For further information see section '3.13. Advanced Debugging Topics' in the Wing IDE help file.

Debugging a Python script

For a walk-through of remote debugging a python script with Wing IDE professional and Personal versions watch the following video - as before, you can watch the video full screen by left clicking the grey rectangle at the far right end of the video control bar.



Debugging a Python plugin

For a walk-through of remote debugging a python plugin with Wing IDE professional and Personal versions watch the following video - as before, you can watch the video full screen by left clicking the grey rectangle at the far right end of the video control bar.



Debugging with PyCharm

PyCharm instructions provided by Nicholas Stevenson.

PyCharm is a Python IDE by JetBrains, and is available from their site here: ["JetBrain's PyCharm]] This walkthrough pertains to Python Scripts, I haven't tackled 701's Python Plugin authoring just yet.

This widget allows you to add a [https://developers.google.com/youtube/player_parameters YouTube video player] to your wiki page. == Using this widget == To insert this widget, use the following code: {{#widget:YouTube|id=videoID}} where 'videoID' is the YouTube video ID For further information, see the [http://www.mediawikiwidgets.org/YouTube widget description page on MediaWikiWidgets.org]. == Parameters == * '''id''' - video id (from the URL) * '''playlist''' - playlist name (starts with PL) - first clip is played ('''id''' is ignored) * '''height''' and '''width''' define view dimensions, 420x350 is default == Sample result == === Single Clip === Embed string = {{#widget:YouTube|id=Ukytqe9pwDM}}

{{#widget:YouTube|id=Ukytqe9pwDM}} === Playlist === Embed string = {{#widget:YouTube|playlist=PL6FD8256CD24CFF1F}}

{{#widget:YouTube|playlist=PL6FD8256CD24CFF1F}}

Setting up Pycharm for Modo

After installing PyCharm, you will need to create a Remote Debugger profile for Modo. Follow these steps to do that.

  1. On PyCharm's top bar, select Run and choose Edit Configurations
  2. Press the green + in the top left hand corner and choose Python Remote Debug
  3. In the following window, name the configuration (Modo 701 for example) and make sure these options are set.
  • Enabled: Single instance only
  • Enabled: Redirect output to console (This will print Modo's Python output inside PyCharm's output window)
  • Disabled: Suspend after connect (If this option is enabled, PyCharm will interrupt modo as soon as it makes the initial connection to PyCharm's debugger, not terribly useful in our situation. )


Copying PyCharm's Debugger Asset in to Modo's Scripts Directory

After you install PyCharm, its Debugger python assets are stored inside its installation directory. To make things easier, lets copy these in to Modo's script directory.

Browse to this location: C:\Program Files (x86)\JetBrains\PyCharm 2.7.1\helpers\ And copy this folder: pydev

In Modo, on the top menu bar choose System->Open User Scripts Folder. Paste the pydev folder in to this directory. In my case, this directory is: C:\Users\nstevenson\AppData\Roaming\Luxology\Scripts


Connecting Modo to PyCharm's Listener

After you have configured PyCharm with a Modo debug profile and copied PyCharm's debugger modfules in to Modo's scripts location, you can now connect Modo and PyCharm together. To start the debug listener, on PyCharm's top menu bar, choose Run and then select Debug Modo 701. Alternatively, you can click the green bug icon on the middle of the main menu bar. The bottom section of PyCharm will expand and you should see that PyCharm is now listening for a connection.


With PyCharm Listening...

From inside Modo, open up a [I]Command History[/I] panel and using the grey gear icon in the top right hand corner, switch its input to Python. After that, enter these two lines in to the Python entry field:

from pydev import pydevd
pydevd.settrace('localhost', port=7720, stdoutToServer=True, stderrToServer=True, suspend=False)

If all goes well, PyCharm's listener should report that it is now connected to a pydev debugger. At this stage, you should be able to import python modules and use break points to debug your scripts.

Your Own Scripts

If you have successfully connected Modo to PyCharm's debugger, you should now be able to set break points and debug your scripts without issue!


A Word of Caution...

There is currently a bug when using PyCharm's Debug Probe. If you attempt to send a command to Modo using the Debug Probe, while Modo is halted with a break point, it will cause Modo to disconnect from PyCharm, requiring you to restart both applications before you can begin debugging again.




Debugging Hints & Tips

  1. When debugging scripts you can make edits/updates to the script without exiting the debugger. Use the python 'reload(modulename)' function from modo's interactive python interpreter to update the script in memory and carry on debugging. Note that this is only true for scripts, not for plugins.


To come ...

  1. remote debugging a python script with Komodo IDE
  2. remote debugging a python plugin with Komodo IDE