|
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. |
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 6.15 and 6.15.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.
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.16 for details.
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.
The project-wide properties dialog contains the following fields:
python
on the command line. If this fails, Wing will search for Python in
/usr/local
and /usr
(on Linux/Unix) or in the registry (on Windows).
PYTHONPATH
is used by Python to locate
modules that are imported at runtime with the import
statement. When
the Use environment checkbox in this area is checked, the
inherited PYTHONPATH
environment variable is used for debug sessions.
Otherwise, is Custom setting is selected, the specified PYTHONPATH
is
used.
Makefile
, before execution is started.
var=value
form
and must be specified one per line in the provided entry area. An entry in
the form var=
(without a value) will cause the given variable to
be undefined. Note that you are operating on the environment inherited
from the IDE and not defining a blank new environment space. When the
Use env radio button is checked, any entered values are ignored and the
inherited environment is used without changes.
debug.use-console
preference. As shipped, Wing
shows a new console each time you start your debug process from within
the IDE. When set to Use Inherited Console, Wing instead reuses
the console from which Wing was launched (if
any) for any command line I/O performed by the debug program. If you are
launching Wing from the Start menu on Windows or similar mechanism on Linux/Unix,
and your debug program uses the command line, set this value to Start New
Console. Otherwise, you will not see your program's output. When Start New
Console is selected, you can optionally cause the console to remain until you
press a key in it by setting the preference debug.persist-console
to
true
, or set a breakpoint at the very end of your program. When Wing
is running in an environment where it cannot allow the debug process to
inherit Wing's console (or there is no console), the Use Inherited Console
option is replaced with Use No Console.
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.
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.
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.16 for details.
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).
Plain clicks on the breakpoint margin will toggle to insert a regular
breakpoint or remove an existing breakpoint.
You can also shift-click to insert a temporary (one-time) breakpoint, control-click to insert a breakpoint and set an ignore count for it, or shift-control-click to insert a conditional breakpoint. When a breakpoint is already found on the line, shift-click will disable or enable it, control-click will set its ignore count, and shift-control-click will set or edit the breakpoint conditional. |
The following types of breakpoints are available:
true
(any non-zero, non-empty,
non-None
value, as defined by Python). You may edit the conditional of
any existing breakpoint with the Edit Breakpoint Condition item in
the Breakpoints menu.Once breakpoints have been defined, you can operate on them in a number of ways to alter their behavior. These operations are available as menu items in the Breakpoints menu, and toolbar icons:
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 sections 6.15 and 6.14 below.
If you are attempting to run your debug process against a non-standard version
of Python, for example one that has been compiled with altered values for
Py_TRACE_REFS or WITH_CYCLE_GC , or that has been altered in other ways, you
may need to recompile the debugger core module. Please refer to section
6.19 for more information.
|
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:
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.
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. |
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, although you may be able to use the expression evaluator, described in
section 6.9, or interactive debug probe, described in section
6.10, to access them.
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
Other indicators such as
In rare cases, a value may contain both a |
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 6.8.3 below.
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. |
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:
locals
or globals
to the selected data value and tries to
reevaluate that path whenever the value may have changed. For example, if you
define a dictionary variable called testdict
in a function and set a
value testdict[1] = 'test'
, the zoomed out view for testdict[1]
would show any value for that slot of testdict
, even if you delete
testdict and recreate it. In other words, value tracking is independent of the
life of any object instances in the data path.
testdict
as
a whole, it would track the contents of that dictionary as long as it exists.
If you were to reassign the variable testdict
to another value, your
zoomed out display would still show the contents of the original dictionary
instance, rather than the new value of the variable testdict
. In other
words, the symbolic path to the value is completely disregarded and only
instance identity is used to track the value. Because it's meaningless to
track immutable types this way, this option is disabled or enabled according
to the values you select to zoom out into a seperate window.
locals
or
globals
, this is the same as tracking the value by symbolic path, because
the parent reference is to the locals
or globals
dictionary itself.
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).
There are a number of ways in which the variable displays can be configured:
Currently, this can be done only by setting the two preferences,
debug.omit-types
and debug.omit-names
. These are
described in section 6.25.
huge
in the
variable display area and cannot be expanded further. The data size thresholds
are controlled with preferences debug.huge-list-threshold
and
debug.huge-string-threshold
, described in section 6.25
and in section 6.8.5.
debug.line-threshold
. If you want all values to be shown
uniformly, this preference should be set to 0
.
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:
debug.network-timeout
preference and then will display the variable
value as <network timeout during evaluate>
.
debug.huge-list-threshold
and
debug.huge-string-threshold
(described in section 6.25). On
the debugger display, oversized sequences and arrays are annotated as
huge
and <truncated>
is prepended to large truncated strings.
To avoid this, increase the value of the threshold preferences, but be
prepared for longer data transfer times. Note that setting these values too
high will cause the debugger to time out if the debug.network-timeout
value isn't also increased.
An alternative for viewing large data values is to use the Expression Evaluator (described in section 6.9) or Interactive Debug Probe (described in section 6.10) to view sub-parts of the data rather than tranferring the whole top-level portion of the value.
__cmp__
and __str__
in your code. If this code has bugs in it,
the debugger may reveal those bugs at times when you would otherwise not see
them.
The rare worst case scenario is crashing of the debug process if flawed C or C++ extension module code is invoked. In this case, the debug session is ended.
Much more usual, but still rare, are cases where Wing encounters an unexpected
Python exception while handling a debug data value. When this happens, Wing
displays the value as <error handling value>
. These errors are not
reported as normal program errors in the Error List dialog. However, running
Wing with debug output as described in section 2.2.6 and
setting preference debug.verbose
to true
or setting a non-None
value for debug.logfile
will allow you to look at the exception that is
being raised (but note that the log file must already exist or else logging
is disabled).
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.
Wing includes an interface for evaluating keyboard-entered expressions and viewing the result of the evaluation within a data display tree. Expressions are evaluated in the context of the current debug stack frame, so this feature is available only when a debug session is active and the debug program has been paused or has stopped at a breakpoint or exception. This also means that the value of the same typed expression may change as you move up and down the call stack in the main debugger window.
The Expression Evaluator item in the Windows menu will display the expression evaluator window. Expressions are typed into the panel at the top of the window and the Evaluate button is used to display the result of the evaluation below. Only expressions that evaluate to a value may be entered. Other statements, like variable assignments, import statements, and language constructs are rejected with an error. These may only be executed using the Interactive Debug Probe described in the next section.
A history list of expressions previously evaluated is also available via popup menu. Expressions selected from this menu are copied into the entry area and optionally evaluated immediately upon selection from the menu (only when the Evaluate Immediately checkbox is checked).
If an exception occurs during expression evaluation, this is reported with the Error List dialog and, if possible, the source location of the error is shown.
You may select from one of three display options when evaluating expressions: A single tree view, a textual view, or a tree/text combo view. These act exactly the same as those accessed from the main debugger window, as described in section 6.8. Once you have changed view modes, you must push the Evaluate button again before the view is filled with data.
In the rare cases where evaluating an expression results in changing the value of local or global variables, your debug program will continue in that changed context. Whenever a value is changed as a result of expression evaluation, the updated value will be propagated into any visible debugger variable display areas because Wing IDE refetches all displayed data values after the evaluation of each expression. However, since you may not notice these changes, caution is then required to avoid creating undesired side-effects in the running debug program. Otherwise, your program may not act as it would have during normal, uninterrupted execution.
Note that in this version of Wing, breakpoints are never reached as a result of expression evaluation, and any exceptions are reported only after the fact. This means that activity in the expression evaluation window has no effect on the debug run position or stack, even though an exception location in source code may in some cases by displayed.
An interactive probe that acts like the Python shell is available for evaluating and executing arbitrary Python code in the context of a debug program. Like the expression evaluator, this acts on the current debug stack frame, and thus is available only when there is an active debug session and the debug program is paused.
This tool is displayed by selecting the Interactive Debug Probe menu item in the Windows menu. It acts much like the Python interpreter when it is invoked from the command line. You may use most of Wing's source editor commands and key bindings within the interactive debug probe window, and can use the up/down arrow keys to traverse a history of recently typed commands.
If commands you type change any local, instance, or global data values, cause modules to be loaded or unloaded, set environment variables, or otherwise alter the run environment, your debug program will continue within that altered state. All visible variable display views are also updated after each line entered in the interactive shell in order to reflect any changes caused by your commands. But since you may not notice these changes, caution is required to avoid creating undesired side-effects in the running debug program. Otherwise, your program may not act as it would have during normal, uninterrupted execution.
One limitation is that private instance variables prefixed by double
underscore (such as self.__my_var
) cannot be directly inspected or
altered within the interactive shell. Python will report that the attribute is
not defined because it internally prefixes the class name where the private
variable is found. These can easily be viewed using the main debugger window
or expression evaluator, or you can look at self.__dict__
as a whole
and then use the fully qualified self._classname__my_var
to access or
alter the value.
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 traceback. This means that activity in the interactive shell window has no effect on the debug run position or stack, even though an exception location in source code may in some cases be displayed.
Preference debug.raise-from-interactive
can be used to determine
whether source code windows will be raised when exceptions occur here. See
section 6.25 for details.
Another 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 6.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
6.25 for details.
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:
stderr
and the program continues to execute, or exits, according to action
taken by the Python interpreter. This behavior is the same as if the
program were running outside of the debugger. You will, however, be
given a post-mortem error and traceback by Wing to distinguish clearly
from cases where a program has exited normally.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.
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.
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 6.25, 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:
stdin
or stdout
will bypass Wing's I/O environment
(which affects only Python-level stdin
and stdout
). This means
that waiting on stdin
in C or C++ code will make the debug process
unresponsive to Wing, causing time out and termination of the debug session if
you attempt to Pause or alter breakpoints at that time. In this case,
redirection of I/O to the Debug Probe and Interactive Shell windows will also
not work.
stdin
from multiple threads in a multi-threaded
program may result in altered character read order when running under the Wing
debugger.
stdin
, even in a
single-threaded program, can result in a race condition with Wing's I/O
multiplexer that leads to out-of-order character reads. This is an unavoidable
result of limitations on multiplexing keyboard and socket I/O on this
platform.
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.
Debug processes normally contact Wing IDE automatically during startup. However, Wing IDE can also attach to debug processes that are already running but not yet in contact with the IDE if the process will allow it. There are two cases where this is useful:
wingdbstub.py
, as described in section 6.15) cannot
reach the IDE at the configured host and port during initial startup, for
example because the IDE is not yet running or was not configured to accept
debug connections.In either case, the IDE can manage any number of detached processes, allowing you to attach to any one process at a time.
Wing will not allow attach/detach functionality unless it has available to it a password that can be used to control access. This is very important because an unsecured debug server provides the client (Wing IDE) full control of the host machine via the Interactive Debug Probe tool. Any Python command can be executed in this way, including programs that compromise the security of your machine and network.
Because Wing sets up an access control password during installation, attach
and detach will work out of the box as long as your debug processes are
launched from Wing IDE, by you from the command line, or in the context of
some service or program that is running under your user name on a machine that
has access to your ~/.wingide
directory (on Linux/Unix) or
WINGHOME\profiles\[username]
(on Windows).
If you plan to debug remotely, please refer to the instructions in section
6.15.3 and 6.15.6. Setting up your remote debugging
to work properly with encryption will also fullfill the requirements of the
attach/detach facility. Note, however, that you can use encryption type
none
to enable attach/detach but disable channel encryption.
The most common way of generating a process to which to attach is to first detach from a debug process. This is done by selecting the Detach from Process item in the Run menu or the detach icon in the toolbar.
Whenever a process is detached, it continues running as if outside of the debugger, without stopping at any breakpoints or exceptions. Even if a process is paused within the debugger at time of detaching from the IDE, the process will start running actively immediately after the IDE disconnects.
The Attach to Process or attach toolbar icon are available whenever no other
debug process is attached to the IDE. This brings up a dialog box that
includes a list of available processes to attach to. The list is built from
hard-wired host/port pairs given with the debug.attach-defaults
preference (('127.0.0.1', 50015)
by default), combined with known
processes that were previously attached to Wing IDE.
Wing updates the list of available processes as debug sessions are terminated from the IDE, as they are seen to exit from the outside while attached to Wing, or when the process cannot be contacted by Wing.
To attach to a process, select it from the list and push the Attach button. You may also type in a host/port value manually if your choice is not on the list (see the next subsection below).
Once you are attached to a process, it continues running until it reaches a breakpoint, unhandled exception, or you push the Pause button or use the Pause item in the Run menu.
If Wing is not running or not listening for connections because Passive Listen has been disabled, then additional processes may be available that are not listed in the Attach dialog.
This is usually the case when debugging externally launched code (that uses
wingdbstub.py
as described in section 6.15). You may use
the kAttachPort
constant in wingdbstub.py
to set the port on
which such processes will listen for attach requests. It is important to set
unique values for this port for each concurrent, externally-launched process.
If the set port is in use, a random port number will be used instead and it
may be difficult to determine this number if the process cannot initially
contact Wing IDE to register.
In any case, any unregistered debug process can be reached from Wing IDE by
typing the host/port into the Attach dialog text areas. If you find yourself
typing a host/port value often, it is best to add that value to the
debug.attach-defaults
preference.
Note that improperly configuring wingdbstub.py
can also result in
failure to reach the IDE during startup, since the port used in your
configured kWingHostPort
must match that set in the Wing IDE
debug.network-port
preference. See section 6.15 to
work through your configuration before resigning to attaching manually.
Currently, Wing supports attaching only to a single debug process at a time. Whenever you detach from a process, it begins free-running and will not stop at any breakpoints or non-fatal exceptions. This limits what can be done with detach/attach from a single copy of Wing. If you wish to actively debug two processes at once, simultaneously controlling stepping, breakpoint activation, and execution (as in a client/server network program), it is best to run two copies of Wing at once.
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.
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:
wingdbstub.py
from the Wing IDE installation directory into
the same directory as your debug program.
.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.
import wingdbstub
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.
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.
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).
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:
kWingDebugDisabled=1
This is equivalent to setting the WINGDB_DISABLED
environment variable
before launching the debug program.
kWingHostPort
to specify the network location of Wing IDE,
so the debugger can connect to it when it starts. This is equivalent to
setting the WINGDB_HOSTPORT
environment variable before launching
the debug program. The default value is localhost:50005
. See section
6.15.3 below for details if you need to change this value.
stderr
by setting kSilent
. This is equivalent
to setting the WINGDB_SILENT
environment variable before launching the
debug program. When set to 1
, debugger internal messages are not
printed to stderr
, so they will not appear, for example, in the web
server log file when running CGI scripts. However, to track down problems in
launching the debugger in the first place, you may need to temporarily set
this value to 0
to see the debugger's internal error messages (which
can be quite verbose).
kLogFile
. This is
equivalent to setting the WINGDB_LOGFILE
environment variable before
launching the debug program (use a value of -
to turn off logging to
file). The file is not created if it doesn't already exist, so you will
need to manually create the file to enable logging to it.
kEmbedded
to 1
when debugging embedded scripts. In
this case, the debug connection will be maintained across script invocations
instead of closing the debug connection when the script finishes. When this
is set to 1
, you must call wingdbstub.debugger.ProgramQuit()
before your program exits in order to cleanly close the debug connection
to the IDE. This is equivalent to setting the environment variable
WINGDB_EMBEDDED
.
kAttachPort
to define the default port at which the debug
process will listen for requests to attach (not available in Wing IDE Lite).
This is equivalent to setting the WINGDB_ATTACHPORT
environment
variable before launching the debug program. If this value is less than 0, the
debug process will never listen for attach requests. If it is greater than or
equal to 0, this value is used when the debug process is running without being
in contact with Wing IDE, as might happen if it initially fails to connect to
the above-defined host and port, or if the IDE detaches from the process for a
period of time.
This is described in more detail in section 6.14 above.
kPWFilePath
to define the search path used to find a
.wingdebugpw
file for the debugger. The envrionment variable
WINGDB_PWFILEPATH
will override this setting. This should be a Python
list of strings if set in wingdbstub.py or a list of directories separated by
the path separator (os.pathsep
). The string $<winguserprofile>
may be used to specify the wing profile directory for the user that the debug
process is running as.
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. In this case, you can attach to the process using Attach to Process from the Run menu, as described in section 6.14. |
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. This section describes how this is done with two machines of the same type. More information on working with machines of different type (e.g. Linux and Windows) can be found in section 6.19.
In order to do this, take the following steps:
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.
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.
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.
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.
*.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).
wingdbstub.py
in with your source
files and import it in your Python source as described in section
6.15.
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.
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.
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.
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.
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')], }
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')]
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.
The value
none
is used when a password is specified to control debug process
attach/detach, as described further in section 6.14 above.
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.
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
6.15.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:
wingdbstub.py
as described in section
6.15.1.
wingdbstub.debugger
to
make any of the following calls:
kEmbedded
was set to 1
in wingdbstub.py
.
This makes sure the debug connection to the IDE is closed cleanly.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.
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.
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 profiledef 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 profiledef main(): a = 1
profile.run("import mymodule; mymodule.main()", "profile_tmp")
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: |
__file__
variable in the module name space before
invoking Python's exec
or eval
.
-O
or -OO
optimization options for the Python interpreter. This removes information about
line numbers and source file names, making it impossible to stop at
breakpoints or step through code.
*.pyc
files:
*.pyc
files on disk after they are generated invalidates
the file name stored in the file if it is a partial relative path. This
happens if your PYTHONPATH
or sys.path
contains partial
relative path names.
compileall.py
and some
other utilities that don't record a correct filename in the *.pyc
file.
*.pyc
may contain a mix of each of these paths. If the symbolic link
that was used is subsequently removed, some of the file names become invalid.
__file__
attribute is not an absolute pathname, the source file for the module may
not be found if the current working directory changes.
The fix for all of these problems is to remove the *.pyc
files and
let Python regenerate them from the corresponding *.py
files
with the correct file name information.
Hint: You can open *.pyc
files in most text editors to inspect the
stored file names.
pdb
in code that you are running within the
Wing debugger. The two debuggers conflict because they attempt to use
the same debugger hooks in the Python interpreter.
__import__
in your code, you will break the
debugger's ability to stop at breakpoints unless you call the original
__import__
as part of your code whenever a module is actually imported.
If you cannot call the original __import__
for some reason, it may be
possible to instead use wingdbstub
and then call
wingdbstub.debugger.NotifyImport()
from your import handler.
__file__
in a module's name space to a value other
than its original, Wing will be unable to stop at breakpoints in the module
and may fail to report exceptions to the IDE's user interface.
stdio
calls
instead of using the Python-level facilities, the debug process will remain
unresponsive to Wing IDE while waiting for keyboard input, I/O redirection to
the Debug Probe and Interactive Shell will fail, and you may run into
out-of-order character reads in some cases. Details can be found in section
6.13.
PYTHONPATH
in combination with code that changes the current working
directory can cause Wing to fail to stop on breakpoints and exceptions, to fail
to display source files, or to confuse source files of the same name.
The reason that Wing has problems in these cases is that the module file name available at runtime is a partial relative path name, and this name cannot always be interpreted correctly if the current working directory is changed after the module has been imported.
This can happen in the following specific scenarios:
wingdbstub
, os.chdir()
is called before
wingdbstub
is imported, and you have launched your Python program
without specifying the full path on the command line to the Python
interpreter, for example with python myfile.py
. The work-around for
this case is to invoke using a full path name as in python
/home/myname/myfile.py
or python C:\mydir\myfile.py
wingdbstub
, launch your Python program without
specifying the full path for the top-level file, call
wingdbstub.debugger.SuspendDebug()
, import a set of modules, call
os.chdir()
, and then call wingdbstub.
debugger.ResumeDebug()
.
os.chdir()
is called before the code is executed. Wing will also have
problems if the filename is incorrect.
Unfortunately, there is no way to always distinguish modules loaded in these
ways. To avoid this problem, use full path names in PYTHONPATH
and
sys.path
when importing modules that share the same file name and
convert file names passed to exec
into full path names with
os.path.abspath()
.
Using execfile(), eval(), or exec with a globals dict that contains
__file__
will cause Wing to incorrectly identify that file as a module
that has been reloaded. This usually happens only when execfile() is
called from the top level of a module, where most of the time the
module is in fact being loaded or reloaded so there is no
misidentification. However, in cases where a module load takes a long
time or involves a long-running loop at the top level, this may happen
after edits to the module have been made and saved causing Wing to
mis-identify the module as having been reloaded with the new edits.
This problem can also be triggered if globals with __file__
is
explicitely passed to this calls. It will only occur when the code
object file name is '?', and locals and globals dictionaries are the
same, as they are by default for these calls.
wingdbstub
, if you set
sys.exitfunc
after debugging has been started, the IDE will time out in
on a broken network connection after the debug program exits on an exception.
This only happens for exceptions that look like they will be handled because a
try/except block is present that might handle the exception, but where the
exception is not in the end handled and the debug program exits without
calling StopDebug()
. Work-arounds include setting sys.exitfunc
before importing wingdbstub
or adding a top-level try/except clause
that always calls StopDebug()
before exiting the debug program.
<string>
will prevent the debugger from debugging
that file because it is confused with the default file name used in Python
for code that is not located in a file.
If you have paid for a license, you have access to the source code for Wing IDE. The debug server is written in Python and standard C and can be recompiled and used on platforms other than those supported by Archaeopteryx Software, Inc. When this is done, your debug process runs on a remote host of any type and Wing runs on one of the supported platforms. The remote host does not have to be one that is supported for Wing IDE. For example, the debugger is known to compile and run under FreeBSD, Solaris, and Lynx OS.
Another reason to recompile the debug server is if you are running against an
altered or experimental version of Python. For example, if the macros
Py_TRACE_REFS
or WITH_CYCLE_GC
are altered from the defaults
shipped with Python, the debug server running against that version of Python
will need to be recompiled.
If you run into any problems with the instructions that follow, please send
email to bugs@wingide.com
. We'll help you get things working.
How you port the debug server will vary slightly depending on whether or not your operating system supports shared libraries. If it does, you will compile and build a shared library that resides in the debug server source tree on your debug host. If it does not, you need to rebuild Python from source on your debug host with an added module for the debug server.
Both methods require the following two steps first:
http:www.wingide.com/support/downloads
. In
order to gain access to the source files on our website, you must have your
customer number and access password as emailed to you with your license files.
If your debug host supports shared libraries, take these steps next. If it does not, skip to the next sub-section.
src/debug/server/dbgtracermodule.c src/debug/server/dbgtracermodule.h src/debug/server/dbgtracerhash.c src/debug/server/dbgtracerhash.h src/debug/server/copathname.c src/debug/server/copathname.h src/debug/server/Makefile src/debug/server/setup.pydist
Place copies of these into the WINGHOME/.bin/#.#.#
directory under on
the host where you plan to run your debug program. #.#.#
is the version
of Python that you plan to use for debugging and WINGHOME
is the
directory where you copied the debug server binaries as described in section
6.15.3.
For example, if you created /usr/lib/winghome
on your debug host and
places bin/1.5.0/src/debug/server
and bin/1.5.0/opensource/schannel
there, you would place the source files in bin/1.5.0/src/debug/server
(and not src/debug/server
).
bin/1.5.0/src/debug/server
.
There are three ways to do this, either (a) with the Makefile, (b) with the
distutils script (if you have distutils 1.0.1 or later on your machine), or (c)
with manual compilation. There is no difference in the results of each of these;
choose whichever is most convenient.
If you use the Makefile, you need to change PYPREFIX
and PYINCLUDE
inside the Makefile to match your Python installation. Then type make
.
If you use distutils, you just need to type python setup.pydist build_ext
.
If you want to compile manually, the commands are as follows (but with
the -I
option altered to match the location of your Python's include
directory):
gcc -I/usr/local/include/python1.5 -c dbgtracermodule.c -o dbgtracermodule.o gcc -I/usr/local/include/python1.5 -c dbgtracerhash.c -o dbgtracerhash.o gcc -I/usr/local/include/python1.5 -c copathname.c -o copathname.o gcc -shared -o dbgtracermodule.so dbgtracermodule.o dbgtracerhash.o copathname.o
If you plan to run with more than one version of Python, the above steps must
be repeated for each of the versions, using each of
bin/1.5.0/src/debug/server
, bin/2.0.0/src/debug/server
,
bin/2.1.0/src/debug/server
, bin/2.2.0/src/debug/server
,
and bin/2.3.0/src/debug/server
and
the build configuration for locating the appropriate header files.
When shared libraries are unavailable, you need to rebuild Python in order to statically link the Wing debug tracer into the executable. To do this:
src/debug/server/dbgtracermodule.c src/debug/server/dbgtracerhash.c src/debug/server/dbgtracerhash.h src/debug/server/copathname.c src/debug/server/copathname.h
Place these into the Modules
directory at the top-level of your
Python source tree.
Modules/Setup.local
file and add the following line
to it:
dbgtracer dbgtracerhash.c dbgtracermodule.c copathname.c
./configure
to set up the build
environment.
make
to build your new Python executable.
make install
if you're running Python from
an installed location (such as /usr/local/bin/python
).
Repeat this with each version of Python that you plan to run. Once completed,
the command import dbgtracer
should complete successfully in a Python
script or when typed at the interactive Python prompt.
Once this is done, debugging happens in exactly the same way as any other
remote debugging. See section remotedebugging
for details.
Please drop us a note at info@wingide.com
to let us know what OS
and version you're using with your debug server!
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".
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.
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.
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.
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.
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
).
To add your own non-Python mainloop support, you need to:
_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.
_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.
'.py'
to the list
kSupportedMainloops
in _extensions.py
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 debuggerCopyright (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]
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.
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:
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.
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, '<', '<') outstr = string.replace(outstr, '>', '>') print string.replace(outstr, '', ''), "<BR>" print "</pre>" print "<P>"
cgi.print_environ() print "<BR><BR>"
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.
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.
/var/log/httpd/error_log
. Any errors not seen on the browser are
appended there.
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.
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
.
Wing can debug mod_python code in the same way that it debugs other externally launched code as described in sections 6.15 and 6.15.3 of this manual.
The following web page contains a quick start guide for mod_python and Wing:
http://wingide.com/doc/mod_python
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.
The following preferences exist for controlling Wing IDE's debug facility:
'raise-always'
to always raise the window, 'raise-never'
to never raise the window (except when explicitely opened from the debugger's
stack view), or 'raise-new'
to raise the window only when stepping
into a new file that isn't the same as the file in which the previous
known run location was found. Default='raise-always'
'raise-always'
or 'raise-never'
. Default='raise-always'
'raise-always'
or 'raise-never'
. Default='raise-always'
false
to disable; true
to enable).
This must be on when the debug program is not launched by Wing IDE
(for example, as with a CGI script). This is the startup default and may
be altered with the Network Mode section of the Run menu. Default=false
('127.0.0.1',)
( ('127.0.0.1', '50015'), )
"*"
to define a default that matches
all otherwise unmatched hosts. The mapping values are arrays of tuples
where each tuple is a (remote_prefix,
local_prefix)
pair. The
remote file name will be a full path name on the debug server file system
and the local file name will be a URL, currently always starting with
file:
. This should be used when files on the remote host are updated
via ftp, NFS, Samba, or other method from master copies on the local host, but
the full path file system locations on the local and remote hosts do not
match. See section 6.15.3 for examples and details.
Default= { '127.0.0.1':[('/','file:/'),]}
true
to allow
Wing to terminate processes that it did not launch but that connected
to its debugger from another locally running process. Whenever this is
set to false
, the Kill menu item and command are disabled when
attached to a debug process launched outside of Wing. Default=false
None
value uses
/usr/bin/env python
on Linux/Unix and the configured default on NT.
Otherwise, give the full path of the Python executable, for example
/usr/local/bin/python
or C:\dev\python
. This preference only
affects programs that are launched from Wing and is overridden by any values
specified in Wing's Project Properties or per-file Debug Properties.
Default=None
'never'
to never
stop, 'always' to always stop, or \verb
'unhandled'! to stop only on
unhandled exceptions. This is just the initial value that Wing
will use; it can be changed after starting Wing using the
Exception Mode item in the Run menu. Default='unhandled'
None
to indicate that the debugger
should listen on all valid network interfaces on the machine. Note that when
a debug session is launched from within Wing IDE (with the Run button),
it always connects from the loopback interface (127.0.0.1).
Default=None
wingdbstub
for debugging on a given host.
The debug server needs to be told the value specified here (as described in
sections 6.15.1 and 6.15.7). Note that this value is
ignored if the debug program is launched from the application, in which
case an available random port number is used instead. Default='50005'
5.0
3.0
true
then all debug program input/output happens in a seperate new
console window, if false
then input/output happens in the window from
which Wing was launched (if any; when Wing is launched from icon, the debug
processes output will be invisible). This value can be overridden from the
per-file or project-wide Debug Properties dialogs. Default=true
Note: On Linux/Unix systems where xterm
runs with setuid, some environment
variables like LD_LIBRARY_PATH
are normally not propagated to the xterm
for security reasons. Wing works around this by propagating any environment
variable starting with LD_
after the xterm has launched. This is done
via a file called spawn-ld-vars-HOST:PORT
stored briefly during startup
in ~/.wingide
(HOST
and PORT
are replaced by the debug
connection port designated by Wing for the debug process).
true
to allow inspection of debug
output after exit of the debug program. This is only relevant when
debug.use-console
is set to true
. Default=false
('function', 'builtin_function_or_method',
'class', 'instance method', 'type', 'module', 'ufunc')
()
55
2000
64000
true
in order
to ask the debug server to use the __members__
attribute on values
that are otherwise opaque. This is useful in interpreting some values
defined and set in C extension modules. This may be turned off in order
to avoid crashing on buggy extension modules. Default=true
'tree'
for a dynamic tree display, 'text'
for a textual display,
and 'combo'
for a combination view like that found in the main debugger
window. These values can be overridden from the right-click popup that appears
over any tree formatted debugger variable display. Default='combo'
'symbolic'
, 'parent-ref'
, and 'ref'
. These
values can be overridden from the right-click popup that appears over any
tree formatted debugger variable display. See section 6.8.3
for more information on these choices. Default='symbolic'
'dec'
for decimal display,
'hex'
for hexadecimal display, or 'oct'
for octal display.
Default='dec'
true
0
to 255
,
that defines the color used behind the current run line during
debugging. Default=(255, 163, 163)
0
to 255
,
that defines the color used around the margin marker for the current
run position during debugging. Default=(255, 0, 0)
true
, Wing may terminate the debug process on large values that
are evaluated in the interactive shell. When set to false
, Wing will do
size checking to avoid such termination but will also cause duplicate
execution of any functionality reached as the result of a __getattr__
method.
sys.stdin
in the debug process should be replaced with a wrapper object
that allows debug commands, such as pause, to be executed while the program is
waiting for user input. The wrapper may cause out-of-order character reads in
programs that use C-level stdio functions to read directly from stdin
,
and it is slower than the normal file object. However, turning this preference
off means that your debug process will not Pause or accept breakpoint changes
while waiting for keyboard input, and any keyboard input that occurs as a side
effect of commands typed in the Debug Probe or Interactive Shell will happen
in unmodified stdin
instead (even though output will still appear in
the Debug Probe and Interactive Shell as always). More information on debug
process I/O can be found in section 6.13.
false
false
Note that currently Wing must be restarted before any altered values take effect.