Wing Tips: Extending Wing with Python (Part 2 of 4)
In this issue of Wing Tips we continue to look at how to extend Wing's functionality, by setting up a project that can be used to develop and debug extension scripts written for (and with) Wing, just as you would work with any other Python code.
If you haven't already read it, you may want to check out Part 1 of this series, where we introduced Wing's scripting framework and set up auto-completion for the scripting API.
Creating a Scripting Project
To debug extension scripts written for Wing, you will need to set up a new project that is configured so that Wing can debug itself. The manual steps for doing this are documented in Debugging Extension Scripts. However, let's use an extension script to do this automatically.
Copy the following Python code and paste it into a new file in Wing, using the File > New menu item:
import sys
import os
import collections
import wingapi
def new_scripting_project():
"""Create a new Wing project that is set up for developing and
debugging scripts using the current instance of Wing"""
app = wingapi.gApplication
def setup_project():
# Set the Python Executable to the Python that runs Wing
proj = app.GetProject()
proj.SetPythonExecutable(None, sys.executable)
if not __debug__:
from proj.attribs import kPyRunArgs
app.fSingletons.fFileAttribMgr.SetValue(kPyRunArgs, None,
('custom', '-u -O'))
# Add Wing's installation directory to the project
proj.AddDirectory(app.GetWingHome())
# Set main debug file to Wing's entry point
wingpy = os.path.join(app.GetWingHome(), 'bootstrap', 'wing.py')
proj.SetMainDebugFile(wingpy)
# Setup the environment for auto-completion on the API and some additional
# values needed only on macOS; use OrderedDict because later envs depend
# on earlier ones
env = collections.OrderedDict()
env['PYTHONPATH'] = os.path.join(app.GetWingHome(), 'src')
if sys.platform == 'darwin':
runtime_dir = os.path.join(app.GetWingHome(), 'bin', '__os__', 'osx')
files = os.listdir(runtime_dir)
for fn in files:
if fn.startswith('runtime-qt'):
qt_ver = fn[len('runtime-'):]
break
env.update(collections.OrderedDict([
('RUNTIMES', runtime_dir),
('QTVERSION', qt_ver),
('QTRUNTIME', '${RUNTIMES}/runtime-${QTVERSION}'),
('SCIRUNTIME', '${RUNTIMES}/runtime-scintillaedit-${QTVERSION}'),
('DYLD_LIBRARY_PATH', '${QTRUNTIME}/lib:${SCIRUNTIME}/lib'),
('DYLD_FRAMEWORK_PATH', '${DYLD_LIBRARY_PATH}'),
]))
app.GetProject().SetEnvironment(None, 'startup', env)
# Create a new project; this prompts the user to save any unsaved files first
# and only calls the completion callback if they don't cancel
app.NewProject(setup_project)
new_scripting_project.contexts = [wingapi.kContextNewMenu('Scripts')]
Save this to a file named utils.py or any other name ending in .py in the scripts directory that is located inside Wing's Settings Directory, as listed in Wing's About box. Then select Reload All Scripts from the Edit menu to get Wing to discover the new script file. Once that's done, Wing monitors the file and will reload it automatically if you edit it and save changes to disk.
You can now create your project with New scripting project from the Scripting menu that should appear in the menu bar:
This prompts to save any edited files before closing the current project, and then creates and configures the new project.
Debugging Extension Scripts
Now you're ready to develop and debug extension scripts with Wing. Try this now by appending the following to the script file that you created in the previous section:
import wingapi
def hello_world():
wingapi.gApplication.ShowMessageDialog("Hello", "Hello world!")
hello_world.contexts = [wingapi.kContextNewMenu("Scripts")]
Save this to disk and then set a breakpoint on the third line, on the call to ShowMessageDialog.
Next, uncheck the Projects > Auto-reopen Last Project preference so that the debugged copy of Wing opens the default project and not your already-open scripting project:
Then select Start/Continue from the Debug menu to start up a copy of Wing running under its own debugger. This copy of Wing should also contain a Scripts menu in its menu bar, with an item Hello world:
Select that and you will reach the breakpoint you set in the outer instance of Wing (the one you started debug from):
You will see and can navigate the entire stack, but Wing will not be able to show source files for most of its internals. If you need to see the source code of Wing itself, you will have to obtain the source code as described in Advanced Scripting.
That's it for now! In the next Wing Tip we'll look look at how extension scripts can collect arguments from the user.
Share this article: