<type>documentation</type>
<domain>scripting</domain>
<id>advanced</id>
<title>Advanced Scripting</title>
<date>$Date$</date>
<version>$Revision$</version>
<product>per+</product>

While Wing's API will remain stable across future releases of the IDE, not all
functionality is exposed by the API. Scripts can also be written to reach through Wing's
API into internal functionality that may change from release to release, but in most cases
stays the same. The most common reason to reach through the API is to add a new tool panel
to Wing.

An example of this can be seen in the disabled ``pylintpanel.py`` script, which is located
in the ``scripts`` directory inside the ``Install Directory`` listed in Wing's `About box
<script:about-application>`__.

Working with Wing's Source Code
-------------------------------

More advanced scripts like those that define a new tool are be easier to develop if Wing
is run from its source code, usually as a debug process that is controlled by another copy
of Wing.

To obtain Wing's source code, you must have a valid license to Wing Pro and must fill out
and submit a `non-disclosure agreement
<https://wingware.com/pub/wingide/support/source-non-discl.pdf>`__. Once this is done, you
will be provided with access to the source code and further instructions.

How Script Reloading Works
--------------------------

Advanced scripters working outside of the API defined in ``wingapi.py`` should note that
Wing only clears code objects registered through the API. For example, a script-added
timeout (using ``CAPIApplication.InstallTimeout()`` method) will be removed and re-added
automatically during reload, but a tool panel added using Wing internals will need to be
removed and re-added before it updates to run on altered script code. In some cases, when
object references from a script file are installed into Wing's internals, it will be
necessary to restart Wing.

Script files that define ``_no_reload_scripts`` at the top level of the module will never
be reloaded or unloaded. Files that define ``_ignore_scripts`` or that exist outside of
the script path are also never reloaded.

Here is how reloading works:

1) All currently loaded script files are watched so that saving the file from an editor
   will cause Wing to initiate reload after it has been saved.
  
2) When a file changes, all scripts in its directory will be reloaded.
  
3) Wing removes all old scripts from the command registry, unregisters any timeouts set
   with ``CAPIApplication.InstallTimeout()``, and removes any connections to preferences,
   attributes, and signals in the API.
  
4) Next ``imp.find_module`` is used to locate the module by name.

5) Then the module is removed from ``sys.modules`` and reloaded using ``imp.find_module``
   and a module name that prepends ``internal_script_`` to the module name, in order to
   avoid conflicting with other modules loaded by the IDE.
   
6) Wing executes the top level of the module as normal when importing a module in Python.
   This may cause signal connections and other calls to the API to occur.
  
7) If module load fails due to an error in the code, any timeouts or other connections
   registered by the module during partial load are removed and the module is removed 
   from ``sys.modules``.
  
8) If the module contains ``_ignore_scripts``, then any timeouts or other connections are
   removed and scripts in the file are ignored.
  
9) Otherwise, Wing adds all the script-defined commands in the module to the command
   registry and loads any sub-modules in the same way, if the module is a package 
   with ``__init__.py``.
  
Note that reloading is by design slightly different than Python's builtin ``reload()``
function: Any old top-level symbols are blown away rather than being retained. This places
some limits on what can be done with global data: For example, storing a database
connection will require re-establishing the connection each time the script is reloaded.

