<type>how-to</type>
<domain>install</domain>
<id>modo</id>
<title>Using Wing with Modo</title>
<date>$Date: 2006-05-26 17:43:42 -0400 (Fri, 26 May 2006) $</date>
<product>pro+</product>
<summary>Tips for using Wing with Python code running under Foundry's Modo, a commercial 3D modeling, animation, texturing, and rendering application.</summary>

.. image:: /images/screenshots/wing7-screenshot-dark.png
  :alt: Wing Screen Shot
  :width: 574
  :height: 423
  :popup: 1

`Wing Pro <https://wingware.com>`__ is a Python IDE that can be used to develop, test, and
debug Python code written for `Modo <https://www.foundry.com/products/modo>`__, a
commercial 3D modeling, animation, texturing, and rendering application..

If you do not already have Wing Pro installed, `download it now <https://wingware.com/downloads/wingpro>`__.

This document describes how to configure Wing for Modo. To get started using Wing as your
Python IDE, please refer to the tutorial in Wing's ``Help`` menu or read the `Quickstart
Guide <ref:howtos/quickstart>`__.
  
Debugging Setup
---------------

When debugging Python code running under ``Modo``, the debug process is initiated from
outside of Wing, and must connect to the IDE. This is done with ``wingdbstub`` according
to the detailed instructions in the `Debugging Externally Launched Code
<ref:debug/debugging-externally-launched-code>`__ section of the manual. In summary, you
will need to:

1) Copy ``wingdbstub.py`` from your Wing installation into a directory that will be on the
   ``sys.path`` when Python code is run by Modo. You may need to inspect that (after
   ``import sys``) first from Modo, or you can add to the path with ``sys.path.append()``
   before importing ``wingdbstub``.

2) Because of how ``Modo`` sets up the Python interpreter, be sure to set ``kEmbedded=1``
   in your copy of ``wingdbstub.py``

3) In your code, where you initiate debugging, use the debugger API to ensure the debugger
   is connected to the IDE before any other code executes, as follows:

.. python::

    import wingdbstub
    wingdbstub.Ensure()

4) In some cases you may need to edit ``wingdbstub.py`` to set ``WINGHOME`` to point to
   the directory where Wing is installed. This is usually set up automatically by Wing's
   installer, but won't be if you are using the ``.zip`` or ``.tar`` installation of Wing. Note that if
   you edit ``wingdbstub.py`` after Modo has already imported it then you will need to
   restart Modo to get it to import the modified ``wingdbstub``.

5) Then click on the bug icon in the lower left of Wing's window and make sure that ``Accept
   Debug Connections`` is checked.
   
At this point, you should be able to reach breakpoints by causing the scripts
to be invoked from Modo. 

However, as of early 2024, running a script in Modo does not set up the file
name in the compiled Python code correctly, so breakpoints only work in
modules that are imported into your top-level script (the one that Modo
imports and runs). This limitation is easily worked around by simply placing
your code in another file and importing that file into the top-level script.
For example, if the script Modo runs is ``myscript.py`` then you might put
all your code in ``myscript_impl.py`` and change ``myscript.py`` to contain
only ``import myscript_impl``.

Once debugging starts, when a breakpoint or exception is reached, Wing should come to the
front and show the place where the debugger stopped. Although the code is running inside
Modo, editing and debugging happens inside Wing.

Reloading Code into Modo
------------------------

By default you'll need to restart Modo before changes you have made to files
imported by your scripts will be seen by Modo. This is a result of Python
only being loaded once at startup in Modo, so previously executed imports
will not be reloaded if the underlying code has changed. 

Since you cannot stop at breakpoints in top-level Modo scripts (as noted
above) this will affect most of your code and can get annoying.

A better way to approach this is to write a small utility ``dbgsupport.py`` with
the following content:

.. python::

   import sys
   
   def import_module(module_name):
       if module_name in sys.modules:
           del sys.modules[module_name]
       module = __import__(module_name)
       return module

Then you can replace ``import myscript_impl`` in your top-level Modo script with code
like this:

.. python::

   from dbgsupport import import_module
   myscript_impl = import_module('myscript_impl')

Now every time you run your script it will be using the latest version of the
file ``myscript_impl.py`` from disk, even if you don't restart Modo.

There are some limitations to reloading modules like this. For example if
other code holds onto references to functions, classes, methods, or other
values in ``myscript_impl``, then those will not be updated automatically as
the module reloads. Also, if your code stores state somewhere outside of the
module, then that will not be cleared or reloaded unless done explicitly by
the new module import. In most cases, you won't run into these limitations
but it's a good idea to be mindful about how resources in your reloaded
modules are used.

Related Documents
-----------------

For more information see:

* `Modo <https://www.foundry.com/products/modo>`__ website

* `Quickstart Guide <ref:howtos/quickstart>`__ contains additional basic information
  about getting started with Wing.
  
* `Tutorial <ref:intro/tutorial>`__ provides a gentler introduction to Wing's features.

* `Wing Reference Manual <ref:manual>`__ documents Wing in detail.
