Scripts are syntactically valid Python with certain extra annotations and structure that are used by Wing to determine which scripts to load and how to execute them.
Only functions defined at the top level of the Python script are treated as commands, and only those that start with a letter of the alphabet. This allows the use of _ prefixed names to define utilities that are not themselves commands, and allows use of Python classes defined at the top level of script files in the implementation of script functionality.
In most cases additional information about each script def is provided via function attributes that define the type of arguments the script expects, whether or not the command is available at any given time, the display name and documentation for the command, and the contexts in which the script should be made available in the GUI.
The following are supported:
- arginfo -- This defines the argument types for any arguments passed to the script. It is a dictionary from the argument name to an ArgInfo specification (described in more detail below) or a callable object that returns this dictionary. Argument information is used by Wing to drive automatic collection of argument values from the user. When this is missing, all arguments are treated as strings.
- available -- This defines whether or not the script is available. If missing, the command is always available. If set to a constant, the truth value of that constant defines availability of the script. If set to a callable object, it is invoked with the same arguments as the script itself and the return value determines availability.
- label -- The label to use when referring to the command in menus and elsewhere. When omitted, the label is derived from the command name by replacing underscores with a space and capitalizing each word (cmdname.replace('_', ' ').title())
- doc -- The documentation for the script. Usually, a docstring in the function definition is used instead.
- contexts -- The contexts in which the script will be added in the GUI, a described in more detail below.
- plugin_override -- Used in scripts that are designated as plugins to indicate that a command should be enabled even if the plugin is not. It should be set to True.
Argument information is specified using the CArgInfo class in the Wing API (wingapi.py inside bin in the Wing installation, although the class is imported from Wing's internals) and the datatype and formbuilder modules in Wing's wingutils package. The source code for this class and support modules is only available in the source distribution, although most use cases are covered by the following.
CArgInfo's contructor takes the following arguments:
- doc -- The documentation string for the argument
- type -- The data type, using one of the classes descended from wingutils.datatype.CTypeDef (see below for the most commonly used ones)
- formlet -- The GUI formlet to use to collect the argument from the user when needed. This is one of the classes descended wingutils.formbuilder.CDataGui (see below for the most commonly used ones).
- label -- The label to use for the argument when collected from the user. This argument may be omitted, in which case Wing builds the label as for the label function attribute described above.
Commonly Used Types
The following classes in wingutils.datatype.py cover most cases needed for scripting:
- CBoolean -- A boolean value. Constructor takes no arguments.
- CType -- A value of type matching one of the parameters sent to the constructor. For example, CType("") for a string, CType(1) for an integer, and CType(1.0, 1) for a float, or an integer.
- CValue -- One of the values passed to the constructor. For example CValue("one", "two", "three") to allow a value to be either "one", "two", or "three".
- CRange -- A value between the first and second argument passed to the constructor. For example, CRange(1.0, 10.0) for a value between 1.0 and 10.0, inclusive.
Additional types are defined in wingutils.datatype.py, but these are not usually needed in describing scripting arguments.
Commonly Used Formlets
The following classes in guiutils.formbuilder.py cover most of the data collection formlets needed for scripting:
CSmallTextGui -- A short text string entry area with optional history, auto-completion, and other options. The constructor takes the following keyword arguments, all of which are optional:
max_chars -- Maximum allowed text length (-1=any, default=80) history -- List of strings for history (most recent 1st) or a callable that will return the history (default=None) choices -- List of strings with all choices, or a callable that will take a fragment and return all possible matches (default=None) partial_complete -- True to only complete as far as unique match when the tab key is pressed. Default=True. stopchars -- List of chars to always stop partial completion. Default='' allow_only -- List of chars allowed for input (all others are not processed). Set to None to allow all. Default=None auto_select_choice -- True to automatically select all of the entry text when browsing on the autocompleter (so it gets erased when any typing happens). Default=False. default -- The default value to use. Default='' select_on_focus -- True to select range on focus click; false to retain pre-focus selection. Default=False editable -- True to allow editing this field. Default=True.
CLargeTextGui -- A longer text string. The constructor takes no arguments.
CBooleanGui -- A single checkbox for collecting a boolean value. The constructor takes no arguments.
CFileSelectorGui -- A keyboard-driven file selector with auto-completion, optional history, and option to browse using a standard file open dialog. The constructor takes the following keyword arguments:
want_dir -- True to browse for a directory name (instead of a file name). Default=False. history -- Optional list with history of recent choices, most recent first. Default=() default -- The default value to use. Default=''
Additional formlet types are defined in guiutils.formbuilder.py but these are not usually needed in collecting scripting arguments.
CPopupChoiceGui -- A popup menu to select from a range of values. The constructor takes a list of items for the popup. Each item may be one of:
None -- A divider string -- The value. The label used in the menu is derived: label = value.replace('_', ' ').title() (value, label) -- The value and label to use in menu. (value, label, tip) -- The value, label, and a tooltip to show when the user hovers over the menu item.
CNumberGui -- A small entry area for collecting a number. The constructor takes these arguments (all are required):
min_value -- The minimum value (inclusive) max_value -- The maximum value (inclusive) page_size -- Increment when scroller is used to browse the range num_decimals -- Number of decimal places (0 to collect an integer)
Additional formlets for collecting data are defined in guiutils.formbuilder.py, but these are not usually needed for scripting.
Magic Default Argument Values
Wing treats certain defaults values specially when they are specified for a script's arguments. When these default values are given, Wing will replace them with instances of objects defined in the API. This is a convenient way for the script to access the application, debugger, current project, current editor, and other objects in the API. All the default values are defined in the wingapi.py file, as are the classes they reference.
- kArgApplication -- The CAPIApplication instance (this is a singleton). Also accessible as wingapi.gApplication.
- kArgDebugger -- The currently active CAPIDebugger. Also accessible as wingapi.gApplication.GetDebugger().
- kArgProject -- The currently active CAPIProject. Also accessible as wingapi.gApplication.GetProject().
- kArgEditor -- The currently active CAPIEditor. Also accessible as wingapi.gApplication.GetActiveEditor().
- kArgDocument -- The CAPIDocument for the currently active editor. Also accessible as wingapi.gApplication.GetActiveDocument().
Scripts can use the contexts function attribute to cause Wing to automatically place the script into certain menus or other parts of the GUI. The following contexts are currently supported (they are defined in wingapi.py):
- kContextEditor -- Adds an item to the end of the editor's context menu (accessed by right clicking on the editor)
- kContextProject -- Adds an item to the end of the project's context menu (accessed by right clicking on the project)
- kContextNewMenu -- Adds an item to a new menu in the menu bar. This is a class whose constructor takes the localized name of the menu to add. The menu is only added if one or more valid scripts with that menu context are successfully loaded.
- kContextScriptsMenu -- Adds an item to the scripts menu, which is shown in the menu bar if any scripts are added to it (this is currently the same as kContextNewMenu("Scripts") but may be moved in the future).
All scripts, under both short and fully qualified name, are always listed along with all internally defined commands in the auto-completion list presented by the Command by Name item in the Edit menu, and in the Custom Key Bindings preference.
Default values for some of the Script Attributes defined above can be set at the top level of the script file, and some additional attributes are also supported:
- _arginfo -- The default argument information to use when no per-script arginfo attribute is present.
- _available -- The default availability of scripts when no available attribute is present.
- _contexts -- The default contexts in which to add scripts when no contexts attribute is present.
- _ignore_scripts -- When set to True, Wing will completely ignore this script file.
- _i18n_module -- The name of the gettext internationalized string database to use when translating docstrings in this script. See below for more information.
- _plugin -- This indicates that the script is a plugin that can be selectively enabled and disabled either according to IDE state or by the user in preferences. See below for more information.
Importing Other Modules
Scripts can import other modules from the standard library, wingapi (the API), and even from Wing's internals. However, because of the way in which Wing loads scripts, users should avoid importing one script file into another. If this is done, the module loaded at the import will not be the same as the one loaded into the scripting manager. This happens because the scripting manager uniquifies the module name by prepending internal_script_ so two entries in sys.modules will result. In practice, this is not always a problem except if global data at the top level of the script module is used as a way to share data between the two script modules. Be sure to completely understand Python's module loading facility before importing one script into another.
Internationalization and Localization
String literals and docstrings defined in script files can be flagged for translation using the gettext system. To do this, the following code should be added before any string literals are used:
import gettext _ = gettext.translation('scripts_example', fallback=1).gettext _i18n_module = 'scripts_example'
The string 'scripts_example' should be replaced with the name of the .mo translation file that will be added to the resources/locale localization directories inside the Wing installation.
Subsequently, all translatable strings are passed to the _() function as in this code example:
kMenuName = _("Test Base")
The separate _i18n_module attribute is needed to tell Wing how to translate docstrings (which cannot be passed to _()).
Currently, the only support provided by Wing for producing the *.po and *.mo files used in the gettext translation system is in the build system that comes with the Wing Pro sources. Please refer to build-files/wingide.py and build-files/README.txt for details on extracting strings, merging string updates, and compiling the *.mo files. On Linux, KDE's kbabel is a good tool for managing the translations.
When a script contains the _plugin attribute at the top level, it is treated as a plugin that can enable/disable itself as a whole and/or be enabled/disabled by the user in preferences.
When _plugin is present, it contains (name, _activator_cb) where name is the display name of the plugin and activator_cb is a function minimally defined as follows for a plugin that is always enabled:
def _activator_cb(plugin_id): wingapi.gApplication.EnablePlugin(plugin_id, True) return True
The _activator_cb can also selectively enable the script by any code that accesses the Wing scripting API. For example, it could set up an instance that connects to signals in the API and calls wingapi.gApplication.EnablePlugin() to enable or disable itself according to project contents, file type in active editor, etc.
When a plugin is inactive, none of its commands are available and any added menus or menu items its adds to the GUI are removed. Plugins may denote particular commands as always available even when the plugin is inactive by setting the _plugin_override function attribute to True.
If the user disables a plugin in the Tools menu, this prevents loading of the plugin, and thus overrides _activator_cb and any _plugin_override attributes for the plugin.