Wing IDE Lite Reference Manual
   
Wing IDE Lite Reference Manual

Version 1.1.10


next up previous contents
Next: A. Command Reference Up: Reference Manual Wing IDE Previous: 4. Source Code Editor


Subsections

5. Debugger

This chapter describes how to use the Wing IDE debugger.


   The Wing debugger consists of two parts: (1) the debug client, represented by the debugger window in Wing IDE, and (2) the debug server, which resides within another process space, possibly on another machine, and communicates with the client via TCP/IP.

The debugger supports launching your application not just from Wing itself but also externally, as with CGI scripts or code running in an embedded scripting facility within a larger application.

When externally launched, your code can attach to the Wing IDE debugger at any point in its execution, and may turn on and off debugging using a simple API.

Because the debugger core is written in optimized C, debug overhead is relatively low; however, you should expect your programs to run about 50% slower within the debugger.


5.1 Quick Start

Wing IDE can be used to debug all sorts of Python code, including scripts and stand-alone applications written with pygtk, wxPython, Tkinter, pyQt, and pygame. Wing can also debug web CGIs including those running under mod_python, Zope products and external methods, and code running in an embedded Python interpreter.

This section describes how to debug stand-alone scripts and applications that can be launched from within Wing IDE. If you wish to debug web CGIs within the web server, Zope code, or embedded Python scripts, please refer to sections 5.12 and 5.12.3.

Before debugging, you will need to install Python on your system if you have not already done so. Python is available from www.python.org.

To debug Python code with Wing, open up the Python file and select Debug from the Run menu. This should run to the first line of the code. Select Continue instead of Debug to run to the first breakpoint, exception, or to program completion (instead of stopping on the first line).

If your Python program does printing or keyboard input, you will want to set the Debug Console setting in the Project Properties to "Start new console". This will cause Wing to create a new seperate window for I/O with the debug process. Setting a breakpoint on the last line of your code is the best way to make sure you can read the program output on exit. Alternatively, set the preference debug.persist-console=true (although this will persist any number of consoles until you press enter in each, so it can be more annoying than using a breakpoint).

In some cases, you may also need to enter a PYTHONPATH and other environment values using the Project Properties dialog available from the Project menu. This can also be used to specify which Python interpreter you wish to use with your debug process. Use this if Wing IDE cannot find Python on your system or if you have more than one version of Python installed.

To set breakpoints, just click on the leftmost part of the margin next to the source code. Conditional, temporary, and ignore counted breakpoints are also available from the Breakpoints menu or with key combinations described later in this chapter.

Note that Wing may report exceptions that you don't normally see when running your debug process. This happens when exceptions are raised that are handled (or accidentally cleared) in C or C++ extension module code. Wing detects all exceptions not handled in Python code. You can check the "Ignore this exception location" checkbox in the Error List window to avoid seeing repeated reports of such exceptions, if they are not of interest.


5.2 Specifying Main Entry Point

Normally, Wing will start debugging in whatever file you have as your front- most window. Depending on the nature of your project, you may wish to specify a file as the default debug entry point.

To do this, right-click on one of your Python files in the Project Manager window and choose the Set As Main Debug File option from the popup menu. This file is subsequently executed whenever you start the debugger, except if you use the Debug Selection in the Project Manager's popup menu.

Note that the project manager will highlight the main entry point in red. You may clear the default main debug file subsequently by using the Clear Main Debug File item in the Project Manager window's popup menu.

Regardless of whether a main debug file is defined, you can also start debugging any open file with Debug Current File in the Debug menu, or by right-clicking on an entry in the project manager and choosing the Debug Selection popup menu item.

The main entry point defined for a project is also used by the source code analysis engine to determine the python interpreter version and python path to use for analysis. Thus, changing this value will cause all source files in your project to be reanalysed from scratch. See section 4.15 for details.


5.3 Debug Properties

In some cases, you will also need to set up some properties to use when debugging. These are set either on a project-wide basis or may be specified on a per-file basis using the main entry point file for the debug session. Project-wide debug properties apply in all cases where a per-file value was not given; otherwise the per-file value overrides the project-wide values.

Only per-file debug properties set on the initially invoked file are used in the debug session. Even if other files with set properties are used in the debug session, any values set for them will be ignored.

Debug properties may be set project-wide from the Properties item in the Project menu. Per-file debug properties may be set from the Current File Debug Properties item in the Run menu, or from the Set Debug Properties item in the right-click popup menu on the project manager.


5.3.1 Project-wide Properties

The project-wide properties dialog contains the following fields:

All of these values are stored in the project file on a per-platform basis. This means that when a project is used on more than one platform (via file sharing or source code control), you must set values seperately for each platform. Wing shows and edits only the values for the platform you are currently running on.

If you are sharing a project file with other developers through a revision control system, and have set Project Type from the Project menu to Shared, it is important to note that the above values are stored in the private branch of the project file. This means that each developer needs to set these values independently, to match the specific environment on their development machine.


5.3.2 Per-file Properties

The per-file debug properties dialog contains all the same fields as are available in the project-wide properties described above, with the following additions:

Custom values entered here will override any project-wide values.

5.3.3 Relation to Source Analysis

The per-file and project-wide debug properties are also used by the source code analysis engine in order to determine the Python interpreter version and PYTHONPATH to use in analysis. For this reason, changing either Python Executable or Python Path in the debug properties dialogs will cause Wing to reanalyse your entire source base from scratch. See section 4.15 for details.

5.4 Setting Breakpoints

Breakpoints can be set on source code by opening the source file and clicking on the breakpoint margin to the left of a line of source code. Alternatively, the Breakpoints menu or the toolbar's breakpoint icons can be used to set or clear breakpoints at the current line of source (where the insertion cursor or selection is located).

5.5 Starting a Debug Session

There are several ways in which to start a debug session from within Wing:

Note that additional options exist for initiating a debug session from outside of Wing and for attaching to an already-running process. These are described in section 5.12 below.

5.6 Flow Control

Once the debugger is running, the following commands are available for controlling further execution of the debug program from Wing. These are accessible from the middle panel of the tool bar or from the Run menu:

When stopped on a given line of code, execution can be stepped line-by-line by using the Step Over, Step Into, and Step Out menu item or tool bar icons:

5.7 Viewing the Stack

Whenever the debug program is paused at a breakpoint or during manual stepping, the current stack is displayed as a list in the top panel of the debugger window. This list shows all stack frames encountered between invocation of the program and the current run position. Outermost stack frames are higher up on the list.

Note that the stack displayed is a concatenation of all Python stack frames seen, and may include discontinuities if your code calls C/C++ or other non-Python code, which in turn makes calls back into Python. In this case, the C/C++ stack frames will be missing but the overall order and flow of invocation should be apparent from those stack frames that are visible.

When the debugger steps or stops at a breakpoint or exception, it selects the innermost stack frame by default.

In order to visit other stack frames further up or down the stack, use the Up Stack and Down Stack items in the Run menu or the up/down tool bar icons. You can also click directly on the surface of the stack in the top panel of the debugger window.

When you change stack frames, the variables views will be changed accordingly, and the current line of code at that stack frame is presented in an editor window.


5.8 Viewing Variables

The Wing IDE debugger provides two ways in which to look at variables: (1) in a hierarchical tree view that can be expanded and collapsed, and (2) in a textual view that can be set to show a desired number of hierarchical levels. These two views are in the second and third debugger window panels, respectively. Note that the relative sizes of these panels can be adjusted by dragging the resize indicators on the dividers between them.


   The variables data displayed by Wing is fetched from the debug server on the fly as you navigate. Because of this, you may experience a brief delay when a change in an expansion or stack frame results in a large data transfer.

5.8.1 Tree View

The tree view contains two top-level entries: (1) locals, which contains all the locals and parameters defined in the currently selected stack frame, and (2) globals, which are scoped to be accessible from all stack frames. Note that in the top-level scope, these two name spaces will be the same and will show the same data.

Simple values, such as strings and numbers, will be displayed in the value column of the tree view area. Strings are always contained in "" (double quotes). Any value outside of quotes is a number or internally defined constant such as None or Ellipsis. Integers can be displayed as decimal, hexadecimal, or octal. Default display mode is changed with preference debug.default-integer-mode and may be altered from the Integer Display area of the Run menu. Once set, the value is remembered in your project file.

Complex values, such as instances, lists, and dictionaries, will be presented with an angle-bracketed type and memory address (for example, <dict 0x80ce388>) and can be expanded by clicking on the expansion indicator in the Variable column. The memory address uniquely identifies the construct. Thus, if you see the same address in two places, you are looking at two object references to the same instance.

Upon expansion of complex views, the position or name of each sub-entry will be displayed in the Variable column, and the value of each entry (possibly also complex values) will be displayed in the Value column. Nested complex values can be expanded indefinitely, even if this results in the traversal of cycles of object references.

Once you expand an entry, the debugger will continue to present that entry expanded, even after you step further or restart the debug session. Expansion state is saved for the duration of your Wing IDE session.


   Some data types, such as those defined only within C/C++ code, or those containing certain Python language internals, cannot be transferred over the network. These are denoted with Value entries in the form <opaque 0x80ce784> and cannot be expanded further.

Values Class-scoped values seen within an instance are shown in italics.

When the debugger encounters a very long string, this is indicated in the Value column by prepending <truncated> to the start of the value. In these cases, the full string can be viewed by clicking on the value and using the Textual View panel at the bottom of the debugger window (explained in section 5.8.2).

Other indicators such as <huge>, <error handling value>, and <network timeout during evaluate> are also used. These are described in section 5.8.5.

In rare cases, a value may contain both a __dict__ attribute and seperate slots defined by keys() and __getitem__() API. Here, the values obtained from keys() are distinguished as ::[key] and ::keys() is shown as well for clarity in cases when keys() returns [].


5.8.1.1 Popup Menu Options

By right-clicking on the surface of the tree view of variables, it is possible to obtain a popup menu that contains several commands useful in navigating data structures. Most of the items in this popup menu act upon the specific data value that was right-clicked upon:

The variable value zooming and tracking features are described in more detail in section 5.8.3 below.


5.8.2 Textual View

The textual view is more useful in some cases than the tree view because (1) it can better display long strings, (2) whole structures are easily accessed without as much visual clutter, and (3) arbitrary sections of the view can be copied and pasted.

The layout textual view is very similar to the tree view, except that per-value expansion and collapse is not available. Instead, a hierarchy of values is displayed up to some selected depth of expansion for the entire set of values.

The Show More and Show Less buttons act like the Expand More and Expand Less popup menu items on the tree view surface, and are enabled and disabled in the same circumstances.


   Using Expand More on the textual variable view, like use of Expand More on the tree view, may result in significant delays on the user interface if expanding large structures to a depth of more than 3 or 4 levels. Caution is advisable in cases where endless traversal of bushy structures is possible.


5.8.3 Tracking Individual Values


   It is possible to zoom variable values out to seperate windows by right-clicking on tree style variable views, either in the main debugger window or in any other zoomed-out tree style view. The resulting window presents the value using a tree, textual, or combination display, according to the configured defaults. The value is tracked during execution and will change on the display according to either its symbolic path, a direct object reference to the value (only for mutable values), or according to a combination of object reference to the parent value and symbolic name for the parent slot.

The display style is controlled with the debug.default-var-view-style preference and can be overridden from the Default Zoom Style item in the popup menu. The selected display styles are the same as those described above: tree, textual, or a combination view containing both types of views, as is found in the main debugger window.

Before using this feature, it's a good idea to understand the subtleties of tracking values during execution. You will likely want to change how this is done during different debug tasks. The supported methods are:

For any of these, if the value cannot be evaluated because it does not exist at any given point in time, the debugger displays <undefined>. This happens when the last object reference to a reference-tracked value is discarded, or if a selected symbolic path is undefined or unevaluable.

The type of tracking that is used is controlled by the debug.default-var-track-style preference and can be overridden from the Default Zoom Tracking item in the popup menu, or by selecting one of the specific Zoom and Track popup menu items (Zoom to Window simply uses the configured default).


5.8.4 Filtering Data Display

There are a number of ways in which the variable displays can be configured:


5.8.5 Problems Handling Debug Data

The Wing debugger tries to handle debug data as gently as possible to avoid entering into lengthy computations or triggering errors in the debug process while it is packaging debug data for transfer. Even so, not all debug data can be shown on the display. This section describes each of the reasons why this may happen:

Wing remembers errors it encounters on debug values and stores these in the project file. These values will not be refetched during subsequent debugging, even if Wing is quit and restarted.

To override this behavior for an individual value, use the Force Reload item in the right-click popup menu of a tree view variable area.

To clear the list of all errors previously encountered so that all values are reloaded after subsequent stepping or restart of the debug session, use the Clear Stored Value Errors item in the Run menu or tree display right-click popup menu. This operates only on the list of errors known for the current debug file, if a debug session is active, or for the main debug file, if any, when no debug process is running.


5.9 Interactive Python Shell

A shell tool is provided for execution of commands and evaluation of expressions outside of your debug program. This is the Interactive Python Shell, which may be accessed from the Windows menu.

Since this shell runs a seperate Python process that is independent of your debug process, it is always enabled and functions without regard to the state of any running debug process. As such, it acts very similarly to a regular command line Python shell.

The Interactive Python Shell always runs the same version of Python as is used for your debug process. This is described in more detail in section 5.3

To clear the state of the Python shell, press the New Session button. This will terminate the external python process and restart it, thus clearing and resetting the state of the shell.

Note that in this version of Wing, breakpoints are never reached as a result of entries typed into the interactive shell, and any exceptions are reported only after the fact with a textual trace back. Preference debug.raise-from-interactive can be used to determine whether source code windows will be raised when exceptions occur here. See section 5.21 for details.

5.10 Managing Exceptions

During debug program execution, the debugger can be asked to stop on exceptions in the same way it would stop at breakpoints or in response to a Pause command.

A number of options for controlling when the debugger will stop on an exception are available from the Run menu's Exception Mode item:

Whenever stopping on an exception, Wing presents an Error List window containing the exception information and backtrace, and stops the program at the point of exception (so that the stack frame and variables for that point are displayed in the debugger window).

Once stopped at an exception, execution can be continued in the same way as at any other time, using the run menu or tool bar, or by selecting Continue Execution in the Error List window.

5.10.1 Filtering Exceptions

The Error List window can be used to indicate to the debugger that the current exception should be omitted from those at which the debugger will stop in the future. To do this, check the checkbox labeled "Ignore this exception location" and push any of the dialog buttons.

This causes the debugger to ignore all exceptions on that line, regardless of type.

The list of ignored exceptions may be cleared to blank subsequently with the Clear Ignored Exceptions item in the Run menu.


5.11 Debug Process Keyboard I/O

While running under the Wing debugger, all traffic to and from Python stdin and stdout, and any calls to input() and raw_input(), are redirected through the debug server machinery. This code does two things: (1) any waits on sys.stdin are multiplexed with servicing of the debug network socket, so that the debug process remains responsive to Wing IDE while waiting for keyboard input, and (2) in some cases, I/O is redirected to another window.

For a debug process launched from within Wing, keyboard I/O always occurs either via the command line window from which Wing was launched (if any) or in a new console that is created before the debug process is started. This can be controlled by the debug.use-console and debug.persist-console preferences, which are described in section 5.21, and by altering the Debug Console setting in Project Properties or the per-file Debug Properties dialog.

Debug processes launched outside of Wing, using wingdbstub, always do their keyboard I/O through the environment from which they were launched (whether that's a console window, web server, or any other I/O environment).

In the case of the Interactive Shell and Debug Probe, I/O is redirected to the Interactive Shell window during the time that a command typed in either of these windows is being processed.

If you are using only Python-level I/O calls in your program, you will not need to be aware of the way Wing alters your debug program's I/O environment, because it mimics the environment found outside of the debugger. There are however several cases that can affect users that bypass Python-level I/O by doing C/C++ level I/O from within an extension module:

If you run into a problem with keyboard I/O, you can turn off Wing's multiplexer by setting the debug.use-stdin-wrapper preference to false. Once that is done, I/O will work properly but the debug process will remain unresponsive to Pause or breakpoint commands from Wing IDE whenever it is waiting for input, either at the C/C++ or Python level. Also, in this case keyboard input invoked as a side effect of using the Command Prompt and Interactive Shell will happen through unmodified stdin instead of within the Wing windows, even though you will still see program output in the Command Prompt and Interactive Shell windows.


5.12 Debugging Externally Initiated Processes

This section describes how to start debugging from a process that is not launched by Wing. Examples of debug code that is launched externally include CGI scripts running under a web server, or embedded Python scripts running inside a larger application.


5.12.1 Importing the Debugger Stub

The following step-by-step instructions can be used to start debugging in externally launched code that is running on the same machine as Wing IDE:

  1. Copy wingdbstub.py from the Wing IDE installation directory into the same directory as your debug program.

  2. In come cases, you will also need to copy the file .wingdebugpw from your Wing profiles directory (profiles/[username] inside your installation on Windows, and ~/.wingide on Posix) into the same directory as wingdbstub.py. This is needed when running the debug process as a different user or in a way that prevents the debug process from reading the .wingdebug.pw file from within your profiles directory.

  3. At the point where you want debugging to begin, insert the following source code:

    import wingdbstub
           

  4. Make sure the Wing IDE preference debug.passive-listen is set to true and (re)launch the IDE, or use the Network Mode section of the Run menu to turn on passive listening.

  5. Set any required breakpoints in your Python source code.

  6. Initiate the debug program from outside Wing IDE, for example with a CGI invocation from your web browser, if the program is a CGI script. You should see Wing's status bar change from "Debugger: Ready and listening" to "Debugger: Program running".

    Make sure that you are running the Python interpreter without the -O option. The debugger cannot determine line numbers and thus cannot do anything meaningful when optimization is turned on.

  7. The debugger should stop at the first breakpoint or exception found and display either "Debugger: Program paused" or "Debugger: Program exception". If no breakpoint or exception is reached, the program will run to completion, or you can use the Pause command in the Run menu.


   In some cases, you may wish to disable termination of debug processes that were launched from outside of Wing IDE. Wing recognizes externally launched processes and can disable the Stop Debugging toolbar icon and Run menu item in these cases if the debug.enable-kill-external preference is set to false.

If you have problems making this work, try setting kSilent=0 variable in wingdbstub.py and launch the Python code from the command line where you can see its error output. Or, set kLogFile in wingdbstub.py to the name of a file to receive error logging information (the file must exist before Wing will log to it).

5.12.2 Server-side configuration

In some cases you may also need to alter other preset configuration values at the start of wingdbstub.py. These values completely replace any values set in Wing's project-wide or per-file debug properties, which are relevant only when the debug program is launched from within Wing. The following options are available:

Setting any of the above-described environment variable equivalents will override the value given in the wingdbstub.py file.


   Whenever the debugger cannot contact Wing IDE (for example, if the IDE is not running or is listening on a different port), the debug program will be run without any debugger. This is useful since debug-enabled CGIs and other programs should work normally when Wing is not present.


5.12.3 Remote Debugging

The description above covers only the case where you are running Wing and the debug code on the same machine. You can also ask the debugger to connect remotely over the network.

In order to do this, take the following steps:

  1. First set up Wing IDE to successfully accept connections from another process within the same machine, as described in section 5.12.1 above. You can use any Python script for testing this until you have values that work.

  2. Optionally, alter the debug.network-server preference to the name or IP address of the network interface on which the IDE listens for debug connections. The default for this is None, which indicates that the IDE should listen on all the valid network interfaces on the host.

  3. Optionally, alter the preference debug.network-port to the TCP/IP port on which the IDE should listen for debug connections. This value may need to be changed if multiple copies of Wing IDE are running on the same host.

  4. Set the debug.passive-hosts preference to include the host on which the debug process will be run. For security purposes, Wing will reject connections if the host isn't included here.

  5. Next install Wing IDE on the machine on which you plan to run your debug program.

    Creating an entire installation is the easiest approach. An alternative is to copy only the debug server code out of your primary Wing installation. This encompasses all of the following under WINGHOME:

    
    bin/wingdb.py
    bin/1.5.0/src/debug/server
    bin/1.5.0/opensource/schannel
    bin/2.0.0/src/debug/server
    bin/2.0.0/opensource/schannel
    bin/2.1.0/src/debug/server
    bin/2.1.0/opensource/schannel
    bin/2.2.0/src/debug/server
    bin/2.2.0/opensource/schannel
    bin/2.3.0/src/debug/server
    bin/2.3.0/opensource/schannel
    

    Be sure to copy these directories from a Wing installation on the same type of host, so that on Linux/Unix you include *.so extension modules, on Windows *.pyd extension modules, and so forth. If you're only using one version of Python, you can omit the directories for the other versions that you are not using.

  6. Next, transfer copies of all your debug code so that the source files are available on the host where Wing IDE will be running and at least the *.pyc files are available on the debug host.

    During debugging, the client and server copies of your source files must match or the debugger will either fail to stop at breakpoints or stop at the wrong place, and stepping through code may not work properly.

    Since there is no mechanism in Wing IDE for transferring your code, you need to use NFS, Samba, FTP or some other file transfer mechanism to keep the remote files up to date as you edit them in Wing.

    You may also need to set up a file location map, as described in the next section (you can safely skip this for now until you get the basics working).

  7. On your debug host, copy wingdbstub.py in with your source files and import it in your Python source as described in section 5.12.

  8. If you didn't copy wingdbstub.py out of a complete installation of Wing IDE on the debug host, you will need to set kWingHome to match the location where you have copied the debug server code on your debug host.

  9. In wingdbstub.py on your debug host, set kWingHostPort to point to the host where Wing IDE will be running. The host in this value must be the IP address of the machine where Wing IDE is running. The port must match the port configured with the debug.network-port preference on the host where Wing IDE is running.

  10. Then restart Wing and try running your program on the debug host. You should see the Wing IDE status area change from "Debugger: Ready and listening" to "Debugger: Program running" (this may be only briefly if your debug process exits quickly).

Now you have the basics working, but may still need to read the next section before you can step through code and stop at breakpoints.

If you have problems getting to this point, set kSilent=0 in wingdbstub.py to print diagnostics to stderr. Alternatively, set kLogFile to ask the debug process to log into that file. Note that the log file must exist before the debug process will log to it.

5.12.4 Defining file location maps

In cases where the full path to your source is not the same on both machines, you also need to set up a mapping that tells Wing where it can find your source files on each machine.

This mapping is defined with the debug.location-map preference, which is a Python dictionary that defines file location mappings for one or more debug hosts.

The dictionary keys are dotted-quad ip addresses for debug hosts. One dictionary key may be set to "*" to define a default mapping for all hosts that are not otherwise specified in the location map.

The dictionary values are arrays of tuples where each tuple is a (remote_prefix, local_prefix) pair. The remote file name will be a full path on the debug server's file system. The local file name will be a URL, currently always starting with file:. The local file is a URL and thus should not contain backslashes (\), even if the local host is a Windows machine!

Note that making symbolic links on the client or server will not work as an alternative to using this mapping. This is a side-effect of functionality in the debugger that ensures that debugging works right when symbolic links are present: Internally, source file names are always resolved to their actual full path location.

5.12.4.1 Examples

The best way to understand location mapping is to inspect a few examples.

The default value for debug.location-map is {'127.0.0.1':None} which indicates that all files at top level on the local host should be referred to with file: URLs. This is equivalent to the more verbose {'127.0.0.1':[('/','file:')]}. It converts full paths on the debug server to the client-side URLs without altering any part of the full path.

Here is an example setting for debug.location-map that would be used if running Wing on desktop1 and debugging some code on server1 with IP address 192.168.1.1:


debug.location-map={ \
  '127.0.0.1':None, \
  '192.168.1.1':[('/home/apache/cgi', 'file:/svr1/home/apache/cgi')] \
}

In this example, the same files are located in /home/apache/cgi on server1 and in /server1/home/apache/cgi on desktop1, because the entire file system on server1 is being NFS mounted on desktop1 under /svr1.

Note that the trailing \ is required for line continuation by the preferences file format.

If you are debugging between Windows and Linux or Unix, some care is needed in specifying the conversion paths because of the different path name conventions on each platform. This entry would be used when running Wing IDE on a Linux/Unix host and the debug process on a Windows host with ip address 192.168.1.1:


debug.location-map={ \
  '127.0.0.1':None, \
  '192.168.1.1':[('c:\\src\\ide', 'file:/home/myuser/src/ide')], \
}

Note the double backslashes in the remote path and the use of forward slashes in the local URL specifier.

If running Wing IDE on a Windows host and the debug process on a Linux/Unix host with IP address 192.168.10, the following might be used instead for the same file locations:


debug.location-map={
  '127.0.0.1':None,
  '192.168.1.1':[('/home/myuser/src/ide', 'file:c:/src/ide')],
}

In the case where the Linux/Unix user myuser home directory is mounted via Samba to a Windows machine as the e: drive, the following similar configuration would be used (only the drive letter differs from the above):


debug.location-map={
  '127.0.0.1':None,
  '192.168.1.1':[('/home/myuser/src/ide', 'file:e:/src/ide')],
}

5.12.5 Remote Debugging Example

Here is a simple example that enables debugging a process running on a Linux/Unix host (192.168.1.200) using Wing IDE running on a Windows machine (192.168.1.210).

On the Windows machine, the following preferences must be specified:

debug.passive-listen=true
debug.network-server=None
debug.network-port="50005"
debug.passive-hosts=('127.0.0.1', '192.168.1.200')
       

On the Linux/Unix machine, the following value is needed in wingdbstub.py:

kWingHostPort='192.168.1.210:50005'
       

Once this is done and Wing has been restarted, you should be able to run code that imports wingdbstub on the Linux/Unix machine and see the debug connection establish on the Windows machine.

Then you will need to set up file sharing between the two machines (for example, using Samba) and will need to establish a location map in your Wing IDE preferences on the Windows machine.

If your source code on the Linux/Unix machine is in /home/myuser/mysource and you map /home/myuser to e: on the Windows machine, you would use the following location map in conjunction with the above settings:

debug.location-map=('192.168.1.200': [('/home/myuser/mysource',                                         'file:e:/mysource')]
       


5.12.6 Encrypting the Debug Channel

If you plan to debug over an unsecured network, you may wish to enable Wing's channel encrypter. Currently, the type of encryption used for this is weak, but it is enough to defeat casual packet sniffing and other abuses. Please don't use it for security-critical applications!

To turn on encryption, you need to create a file called .wingdebugpw which contains a single line of text that is used as the password at both ends of the debug channel. The line should be in the form [encrypt]:[password] where [encrypt] is one of none or rotor, and [password] is your password. If you specify only a password and no encryption type, rotor is used by default.

Place a copy of this file into the .wingide directory in your home directory (on Linux/Unix) or WINGHOME\profiles\[username] (on Windows). Whenever this file is present, Wing will enable encryption using the password in the file. You may need to restart Wing after placing, altering, or removing this file.

You will also need to place another copy of this file in the same directory as the remote debug program or within the .wingide directory of the user under which the debug program will run (or WINGHOME\profiles\[username] on Windows).

It is important that both ends of the channel match with respect to whether or not this file is present, what type of encryption is specified, and the password that is given. Passwords are case sensitive. If only one of the files is present or if they do not match, then the debug session will fail to initiate properly, possibly without clear notice of error.

The password is currently stored unencrypted, so it is important to make sure that the file is readable only by trusted users. Usually the best approach is to change the file so it is readable only by a single user (for example with chmod 400 on Linux/Unix), and then change ownership of the file to match the user under which Wing or the debug program will run (for example, with chown on Linux/Unix).

Encryption will also be turned on for Wing-launched debug sessions as long as ~/.wingide/.wingdebugpw (on Linux/Unix) or WINGHOME\profiles\[username]\.wingdebugpw (on Windows) is present and specifies a non-none encryption type. Since an encrypted channel is noticeably slower than an unencrypted channel, you may wish to remove, rename, or alter this file unless you really need encryption.


5.12.7 Full Control via Debug API

A simple API can be used to control debugging more closely, once you have imported wingdbstub.py the first time, as was described in section 5.12.1 above.

This is useful in cases where you want to be able to start and stop debugging on the fly several times during a debug run, for example to avoid debug overhead except within a small sub-section of your code.

To use the API, take the following steps:

  1. Configure and import wingdbstub.py as described in section 5.12.1.

  2. Subsequently, use the instance variable wingdbstub.debugger to make any of the following calls:

Here is a simple usage example:

import wingdbstub
a = 1 # This line is debugged
wingdbstub.debugger.SuspendDebug()
x = 1 # This is executed without debugging
wingdbstub.debugger.ResumeDebug()
y = 2 # This line is debugged again
       

Note that SuspendDebug() and ResumeDebug() can be called as many times as desired, and nested calls will be handled so that debugging is only resumed when the number of ResumeDebug() calls matches the number of SuspendDebug() calls.

5.13 Running Code Without Debug

It is possible to execute files outside of the debugger. This can be done with any Python code, Makefiles, and any other file that is marked as executable on disk. To do this, select the Execute Current File item in the Run menu to execute the currently at-front document, or use the project manager's popup menu item Execute Selected File.

Files executed in this way are run in a seperate process and any input or output occurs within the window from which Wing was launched (or is entirely hidden if Wing was launched from a desktop icon).

This is useful for triggering builds, executing utilities used in development, or even to launch a program that is normally launched outside of Wing and debugged using wingdbstub.py.

Note that files executed in this way are always invoked as if from their enclosing directory and without any parameters. There is currently no facility for specifying parameters or redirecting input/output.

5.14 Using the debugger and Python profiler together


   Profiling under the debugger may yield inaccurate results since the debugger adds overhead that isn't always uniform across your code base.

The Python profiler makes some assumptions about how it is started that conflict with the way the Wing debugger works. Because the debugger can start debugging on the fly in the context of already-running code, it confuses the profiler into using the wrong top-level scope for its activities.

This means that a file like the following will not work:

import profile

def main(): a = 1

profile.run("main()", "profile_tmp")

The profiler will raise an AttributeError on main because it is looking for it in the top-level file, which is not your code when running under Wing.

The way to solve this problem is to explicitely import and run the function you wish to profile, as follows:

import profile

def main(): a = 1

profile.run("import mymodule; mymodule.main()", "profile_tmp")

5.15 Limitations


   There are certain situations that the debugger cannot handle, because of the way the Python programming language works. If you are having problems getting the debugger to stop at breakpoints or to display source as you step through your code, please read through the following limitations:


5.16 Non-Python Mainloop Environments

Because of the way the Python interpreter supports debugging, the debug process may become unresponsive if your debug process is free-running for long periods of time in non-Python code, such as C or C++. Whenever the Python interpreter is not called for long periods of time, messages from Wing IDE may be entirely ignored and the IDE may disconnect from the debug process as if it had crashed. This primarily affects pausing a free-running program or setting, deleting, or editing breakpoints while free-running.

Examples of environments that can spend significant amounts of time outside of the Python interpreter include GUI kits such as Gtk, Qt, Tkinter, WXPython, and some web development tools like Zope. For the purposes of this section, we call these "non-Python mainloops".

5.16.1 Supported non-Python mainloop environments

Wing already supports Gtk, Tkinter, WXPython, and Zope. If you are using one of these, or you aren't using a non-Python mainloop at all, then you do not need to read further in this section.

5.16.2 Working around the problem

If you are using an unsupported non-Python mainloop that normally doesn't call Python code for longer periods of time, you can work around the problem by adding code to your application that causes Python code to be called periodically. For example, under PyQt, add the following code after you have created your QApplication and before your call to exec_loop():

# Hack to burn some Python bytecode periodically so Wing's
# debugger can remain responsive while free-running
timer = QTimer()
def donothing(*args):
  for i in range(0, 100):
    x = i
timer.connect(timer, SIGNAL("timeout()", donothing)
timer.start(500, 0)
       

Similar code can be crafted in most non-Python mainloop environments.

The alternative to altering your code is to write special plug-in support for the Wing debugger that causes the debug server sockets to be serviced even when your debug program is free-running in non-Python code. The rest of this section describes what you need to know in order to do this.

5.16.3 How it works

Wing uses a network connection between the debug server (the debug process) and the debug client (Wing IDE) to control the debug process from the IDE and to inform the IDE when events (such as reaching a breakpoint or exception) occur in the debug process.

As long as the debug program is paused or stopped at a breakpoint or exception, the debugger remains in charge and it can respond to requests from the IDE. Once the debug program is running, however, the debugger itself is only called as long as Python code is being executed by the interpreter.

This is usually not a problem because most running Python program are executing a lot of Python code! However, in a non-Python mainloop, the program may remain entirely in C, C++, or another language and not call the Python interpreter at all for long periods of time. As a result, the debugger does not get a chance to service requests from the IDE. Pause or attach requests and new breakpoints may be completely ignored in this case, and the IDE may detach from the debug process because it is unresponsive.

Wing deals with this by installing its network sockets into each of the supported non-Python mainloops, when they are detected as present in the debug program. Once the sockets are registered, the non-Python mainloop will call back into Python code whenever there are network requests pending.

5.16.4 Writing a Debug Server Hook

For those using an unsupported non-Python mainloop, Wing provides an API for adding the hooks necessary to ensure that the debugger's network sockets are serviced at all times.

5.16.4.1 Overview

If you wish to write support for a non-Python mainloop, you first need to check whether there is any hope of registering the debugger's socket in that environment. Any mainloop that already calls UNIX/BSD sockets select() and is designed for extensible socket registration will work and is easy to support. Gtk and Zope both fell into this category.

In other cases, it may be necessary to write your own select() call and to trick the mainloop into calling that periodically. This is how the Tkinter and WXPython hooks work. Some environments may additionally require writing some non-Python glue code if the environment is not already set up to call back into Python code.

Mainloop hooks are written as a seperate modules that are placed into src/debug/server within WINGHOME. The module _extensions.py also found there includes a generic class that defines the API functions required of each module, and is the place where new modules must be registered (in the constant kSupportedMainloops).

5.16.4.2 Writing Your Own

To add your own non-Python mainloop support, you need to:

  1. Copy one of the source examples (such as _gtkhooks.py) found in src/debug/server, as a framework for writing your hooks. Name your module something like _xxxxhooks.py where xxxx is the name of your non-Python mainloop environment.

  2. Implement the _Setup(), RegisterSocket(), and UnregisterSocket() methods. Do not alter any code from the examples except the code with in the methods. The name of the classes and constants at the top level of the file must remain the same.

  3. Add the name of your module, minus the '.py' to the list kSupportedMainloops in _extensions.py

5.16.4.3 Example

The following is a copy of the Python code that supports socket registration in Gtk. This file is also distributed as source with all copies of Wing, and can be foundin src/debug/server within WINGHOME.

#########################################################################
""" _gtkhooks.py - Gtk socket management hooks for the Wing IDE debugger

Copyright (c) 1999-2001, Archaeopteryx Software, Inc. All rights reserved.

Written by Stephan R.A. Deibel and John P. Ehresman

""" #########################################################################

import _extensions

# The name of the module to watch for that indicates presence of this # supported mainloop environment kIndicatorModuleName = 'gtk'

######################################################################### # GTK-specific support for managing the debug server sockets ######################################################################### class _SocketHook(_extensions._SocketHook): """ Class for managing the debug server sockets: This is used only when gtk is detected as being present in the debuggee's code. """

#----------------------------------- def __init__(self, err): """ Constructor """ _extensions._SocketHook.__init__(self, err) self.__fGtkHandlers = self.__fGtkModule = None

#------------------------------------ def _Setup(self, mod, s, cb_fct): """ Attempt to set up socket registration with the given module reference : This should be a reference to the indicator module for the supported environment. The first socket is registered with given action callback via _RegisterSocket(). Returns the socket if succeeded or None if fails (for example, because the module is not yet fully loaded and we cannot yet use it to start registering sockets. Note that the returned socket may be different than the socket passed in because some environments require a wrapper: The returned socket is then used in place of the original in the debug server code. """

# Check if module is fully loaded as far as the constructs we will need if mod.__name__ != 'gtk' or not hasattr(mod, 'GDK') or not hasattr(mod, 'input_add') or not hasattr(mod, 'input_remove') or not hasattr(mod.GDK, 'INPUT_READ') or not hasattr(mod.GDK, 'INPUT_EXCEPTION'): return None

# Try to register the first socket self.__fGtkModule = mod new_sock = self._RegisterSocket(s, cb_fct) if new_sock == None: self.__fGtkModule = None return None

# Success return new_sock

#----------------------------------- def _RegisterSocket(self, s, cb_fct): """ Function to register a socket with a mainloop: Subsequently the given callback function is called whenever there is data to be read on the socket. Returns the socket if succeeded; None if fails. As in _Setup(), the returned socket may differ from the one passed in, in which case the debug server will substitute the socket that is used in its code."""

# Try to use given module to register the socket: This may still fail # if module is in the process of being imported try:

# Register with GTK cond = self.__fGtkModule.GDK.INPUT_READ | self.__fGtkModule.GDK.INPUT_EXCEPTION handler_id = self.__fGtkModule.input_add(s, cond, cb_fct) self.__fGtkHandlers[s] = handler_id

# Done self.fErr.out("################## Socket registered with gtk: ", s) return s

# Failed but will keep checking except: self.fErr.out("################## 'gtk' module not fully loaded") return None

#----------------------------------- def _UnregisterSocket(self, s): """ Function to unregister a socket with the supported environment. The socket passed in should be the one returned from _Setup() or _RegisterSocket(). """

self.fErr.out("################ Deregistered socket with gtk: ", s) self.__fGtkModule.input_remove(self.__fGtkHandlers[s]) del self.__fGtkHandlers[s]

5.16.4.4 Getting Help

If you are having difficulties writing your non-Python mainloop hooks, please contact our Technical Support group via our website at http://wingide.com/support. We will be happy to assist you, and welcome the contribution of any hooks you may write.

5.17 Hints for Debugging Web CGIs

Debugging CGI scripts can be annoying since any output from your program that is not understood by the web server will cause the server to write an error to its log files rather than displaying anything useful back to the browser.

Here are a few simple suggestions that may help you configure the debugger and verify that things are working correctly:

  1. At the very start of your code, before importing wingdbstub or calling the debug API, insert the following temporary line of code:

    print "Content-type: text/html<html>"
           

    This will cause all subsequent data to be included in the browser window, even if your normal Content-type specifier code is not being reached.

  2. Place a catch-all exception handler at the top level of your CGI code and print exception information to the browser. The following function is useful for inspecting the state of the CGI environment when an exception occurs:

    import sys
    import cgi
    import traceback
    import string
    
    

    #------------------------------------ def DisplayError(): """ Output an error page with traceback, etc """

    print "<H2>An Internal Error Occurred!</H2>" print "<I>Runtime Failure Details:</I><P>"

    t, val, tb = sys.exc_info() print "<P>Exception = ", t, "<br>" print "Value = ", val, "", "<p>"

    print "<I>Traceback:</I><P>" tbf = traceback.format_tb(tb) print "<pre>" for item in tbf: outstr = string.replace(item, '<', '&lt;') outstr = string.replace(outstr, '>', '&gt;') print string.replace(outstr, '', ''), "<BR>" print "</pre>" print "<P>"

    cgi.print_environ() print "<BR><BR>"

  3. If you are using wingdbstub.py, you can set kSilent=0 to receive extra information from the debug server, in order to debug problems connecting back to Wing IDE. This information is written to stderr and thus will be found in the web server's error log file.

  4. If you are using the full debugger API, you can set your CErrStream object to send output either to stdout, stderr, or any other file stream. Use this to send errors to the browser, web server error log, or to a file, respectively.

  5. If you are unable to see script output that may be relevant to trouble-shooting, try invoking your CGI script from the command line. The script may fail but you will be able to see messages from the debug server, when those are enabled.

  6. If all else fails, read your web browser documentation to locate and read its error log file. On Linux with Apache, this is often in /var/log/httpd/error_log. Any errors not seen on the browser are appended there.

  7. Once you have the debugger working for one CGI script, you will have to set up the wingdbstub import in each and every other top-level CGI in the same way. Because this can be somewhat tedious, and because the import needs to happen at the start of each file (in the __main__ scope), it makes sense to develop your code so that all page loads for a site are through a single entry point CGI and page-specific behavior is obtained via dispatch within that CGI to other modules. With Python's flexible import and invocation features, this is relatively easy to do.

5.18 Using Wing with Zope

To debug Zope code, you need to install the WingDBG Zope product into your Zope installation. This will allow you to configure and control debugging from the Zope Management Interface. Once set up, you will be able to debug all requests made to a special debug port. This may be done concurrently with requests made to the default non-debug server port.

For details on installing and using the WingDBG Zope product, please refer to our web site at http://wingide.com/doc/zope.

5.19 Using Wing with mod_python

Wing can debug mod_python code in the same way that it debugs other externally launched code as described in sections 5.12 and 5.12.3 of this manual.

The following web page contains a quick start guide for mod_python and Wing:

http://wingide.com/doc/mod_python

5.20 Using Wing with pygame

Wing can debug pygame programs without any problem. You may need to set your PYTHONPATH and other environment variables in your Project Properties. Then just run your programs inside the Wing IDE debugger.


5.21 Preferences

The following preferences exist for controlling Wing IDE's debug facility:

Note that currently Wing must be restarted before any altered values take effect.


next up previous contents
Next: A. Command Reference Up: Reference Manual Wing IDE Previous: 4. Source Code Editor   Contents



2003-08-28