Bundle Example: Hello World¶
This example describes how to create a ChimeraX bundle
that defines a new command,
hello. The steps in
implementing the bundle are:
bundle_info.xmlcontaining information about the bundle,
Create a Python package that interfaces with ChimeraX and implements the command functionality, and
Install and test the bundle in ChimeraX.
The final step builds a Python wheel that ChimeraX uses to install the bundle. So if the bundle passes testing, it is immediately available for sharing with other users.
Source Code Organization¶
The source code for this example may be downloaded as a zip-format file containing a folder named hello_world. Alternatively, one can start with an empty folder and create source files based on the samples below. The source folder may be arbitrarily named, as it is only used during installation; however, avoiding whitespace characters in the folder name bypasses the need to type quote characters in some steps.
The files in the source code folder are:
hello_world- bundle folder
bundle_info.xml- bundle information read by ChimeraX
src- source code to Python package for bundle
__init__.py- package initializer and interface to ChimeraX
cmd.py- source code to implement
The file contents are shown below.
bundle_info.xml is an eXtensible Markup Language
format file whose tags are listed in Bundle Information XML Tags.
While there are many tags defined, only a few are needed
for bundles written completely in Python.
1<!-- 2ChimeraX bundle names must start with "ChimeraX-" 3to avoid clashes with package names in pypi.python.org. 4When uploaded to the ChimeraX toolshed, the bundle 5will be displayed without the ChimeraX- prefix. 6--> 7 8<BundleInfo name="ChimeraX-HelloWorld" 9 version="0.1" package="chimerax.hello_world" 10 minSessionVersion="1" maxSessionVersion="1"> 11 12 <!-- Additional information about bundle source --> 13 <Author>UCSF RBVI</Author> 14 <Email>email@example.com</Email> 15 <URL>https://www.rbvi.ucsf.edu/chimerax/</URL> 16 17 <!-- Synopsis is a one-line description 18 Description is a full multi-line description --> 19 <Synopsis>Basic example for adding a command</Synopsis> 20 <Description>Basic example code for implementing ChimeraX bundle. 21 22Implements command "hello" to print the string "hello world" in the log. 23 </Description> 24 25 <!-- Categories is a list where this bundle should appear --> 26 <Categories> 27 <Category name="General"/> 28 </Categories> 29 30 <!-- Dependencies on other ChimeraX/Python packages --> 31 <Dependencies> 32 <Dependency name="ChimeraX-Core" version="~=1.1"/> 33 </Dependencies> 34 35 <!-- Python and ChimeraX-specific classifiers 36 From https://pypi.python.org/pypi?%3Aaction=list_classifiers 37 Some Python classifiers are always inserted by the build process. 38 These include the Environment and Operating System classifiers 39 as well as: 40 Framework :: ChimeraX 41 Intended Audience :: Science/Research 42 Programming Language :: Python :: 3 43 Topic :: Scientific/Engineering :: Visualization 44 Topic :: Scientific/Engineering :: Chemistry 45 Topic :: Scientific/Engineering :: Bio-Informatics 46 The "ChimeraX :: Bundle" classifier is also supplied automatically. --> 47 <Classifiers> 48 <!-- Development Status should be compatible with bundle version number --> 49 <PythonClassifier>Development Status :: 3 - Alpha</PythonClassifier> 50 <PythonClassifier>License :: Freeware</PythonClassifier> 51 <!-- ChimeraX classifiers describe supplied functionality --> 52 <ChimeraXClassifier>ChimeraX :: Command :: hello :: General :: 53 Print "hello world" in the log</ChimeraXClassifier> 54 </Classifiers> 55 56</BundleInfo>
The document tag (which contains all other tags)
BundleInfo, whose required
name: the name of the bundle,
version: version of the bundles, usually in the form of major.minor.patch,
package: the name of the Python package where ChimeraX can find the code for this bundle, and
maxSessionVersion: the minimum and maximum sessionf file versions that the bundle supports.
The next few tags supply information about who wrote the bundle, where to find more information on the web, as well as short and long descriptions of what functionality the bundle provides.
Category tags list the categories to which the
bundle belong. These
Category values are used by the
ChimeraX Toolshed when the bundle is contributed to the
repository. (Note that these values are completely distinct
from the category values described below in
Dependency tags list the bundles that must be installed
for this bundle to work. The
ChimeraX-Core bundle is a
pre-installed bundle that provides much of ChimeraX functionality.
For alpha and beta releases, the version number will start from
“0.1” and slowly approach “1.0”. Because ChimeraX Python API
follows semantic versioning rules (newer versions of ChimeraX
are compatible with older ones with the same major version number),
bundles written for earlier versions of ChimeraX will typically
work in later versions as well. This is indicated by the
version attribute of the
Dependency tag for
Dependency tag should be present for each
additional bundle that must be installed. During installation
for this bundle, if any of the bundles listed in
tags are missing, they are automatically installed as well.
Finally, there are
Classifier tags, of which there are two
flavors: Python and ChimeraX. Values for Python classifiers
are the same as those found in standard Python package setup
scripts. Values for
ChimeraXClassifier tags classifiers
follow the same form as Python classifiers, using
separators among data fields.
The first data field must be the string
The second field specifies the type of functionality supplied,
in this case, a command.
For command classifiers, the third field is the name of the
command, in this case,
The fourth field for command classifiers is its category,
in this case,
General. (The category for a command is
reserved for future use but does not currently affect ChimeraX
The final data field for command classifiers is a synopsis
of what the command does, and is shown as help text in the
Commands may be a single word or multiple words.
The latter is useful for grouping multiple commands by
sharing the same first word. ChimeraX also automatically
support unambiguous prefixes as abbreviations. For example,
the user can use
hel as an abbreviation for
if no other command begins with
is not an abbreviation because the
hide command also
All bundle functionality must be listed in in ChimeraX classifiers in order for ChimeraX to integrate them into its user interface. In this example, the bundle only provides a single new command-line interface command. Reference documentation for bundle information tags, and specifically ChimeraX classifiers, is in Bundle Information XML Tags.
src is the folder containing the source code for the
Python package that implements the bundle functionality.
devel command, used for building and
installing bundles, automatically includes all
src as part of the bundle. (Additional
files may also be included using bundle information tags
DataFiles as shown in Bundle Example: Add a Tool.)
The only required file in
.py files are typically arranged to implement
different types of functionality. For example,
is used for command-line commands;
for graphical interfaces;
io.py for reading and saving
1# vim: set expandtab shiftwidth=4 softtabstop=4: 2 3from chimerax.core.toolshed import BundleAPI 4 5 6# Subclass from chimerax.core.toolshed.BundleAPI and 7# override the method for registering commands, 8# inheriting all other methods from the base class. 9class _MyAPI(BundleAPI): 10 11 api_version = 1 # register_command called with BundleInfo and 12 # CommandInfo instance instead of command name 13 # (when api_version==0) 14 15 # Override method 16 @staticmethod 17 def register_command(bi, ci, logger): 18 # bi is an instance of chimerax.core.toolshed.BundleInfo 19 # ci is an instance of chimerax.core.toolshed.CommandInfo 20 # logger is an instance of chimerax.core.logger.Logger 21 22 # This method is called once for each command listed 23 # in bundle_info.xml. Since we only listed one command, 24 # we expect only a single call to this method. 25 26 # We import the function to call and its argument 27 # description from the ``cmd`` module, adding a 28 # synopsis from bundle_info.xml if none is supplied 29 # by the code. 30 from . import cmd 31 desc = cmd.hello_world_desc 32 if desc.synopsis is None: 33 desc.synopsis = ci.synopsis 34 35 # We then register the function as the command callback 36 # with the chimerax.core.commands module. 37 # Note that the command name registered is not hardwired, 38 # but actually comes from bundle_info.xml. In this example, 39 # the command name is "hello", not "hello world". 40 from chimerax.core.commands import register 41 register(ci.name, desc, cmd.hello_world) 42 43 44# Create the ``bundle_api`` object that ChimeraX expects. 45bundle_api = _MyAPI()
__init__.py contains the initialization code that defines
bundle_api object that ChimeraX needs in order to
invoke bundle functionality. ChimeraX expects
class to be derived from
which has one public attribute,
api_version, and these methods:
initialize- invoked when ChimeraX starts up and the bundle needs custom initialization
finish- invoked when ChimeraX exits and the bundle needs custom clean up
register_command- invoked the first time a bundle command is used
register_selector- invoked the first time a bundle chemical subgroup selector is used
start_tool- invoked to display a bundle graphical interface
open_file- invoked when a file of a bundle-supported format is opened
save_file- invoked when a file of a bundle-supported format is saved
fetch_from_database- invoked when an entry is fetched from a network database
get_class- invoked when a session is saved and a bundle object needs to be serialized
api_version attribute should be set to
1. The default
0 and is supported for older bundles.
New bundles should always use the latest supported API version.
This example only provides a single command, so the only method that
needs to be overridden is
register_command. The other methods
should never be called because there are no
bundle_info.xml that mention other types of functionality.
register_command is called once for each command listed in a
ChimeraXClassifier tag. When ChimeraX starts up, it registers
a placeholder for each command in all bundles, but normally does
import the bundles. When a command is used and ChimeraX detects
that it is actually a placeholder, it asks the bundle to register
the run-time information regarding what arguments are expected and
which function should be called to process the command, after which
the command line is parsed and the registered function is called.
Once a command is registered, ChimeraX will not call
register_command for it again.
BundleAPI version 1, the
register_command method is called
with three arguments:
bi- instance of
ci- instance of
logger- instance of
bi provides access to bundle information such as its name, version,
and description. For this example, no bundle information is required
bi is unused.
ci provides access to command information,
and the two attributes used are
synopsis (for setting help text
if none is provided in code) and
name (for notifying ChimeraX of
what function to use to process the command).
logger may be used
to notify users of warnings and errors; in this example, errors will
be handled by the normal Python exception machinery.
The most important line of code in
register_command is the call
chimerax.core.commands.register(), whose arguments are:
name- a Python string for the command name,
cmd_desc- an instance of
chimerax.core.commands.CmdDescwhich describes what command line arguments are expected, and
function- a Python function to process the command.
In this example, the command name comes from the command information
ci.name. Both the argument description and the Python
function are defined in another package module:
The argument description comes from
augmented with help text from
ci.synopsis. The command-processing
function also comes from the same module,
The arguments that
cmd.hello_world will be called with are
determined by the attributes of
cmd.hello_world_desc and is
register_command and other
BundleAPI methods are static
methods and are not associated with the
The intent is that these methods remain simple and should not need
other data. If necessary, data can be stored as attributes of
and the static methods can refer to the instance explicitly.
1# vim: set expandtab shiftwidth=4 softtabstop=4: 2 3from chimerax.core.commands import CmdDesc 4 5 6def hello_world(session): 7 # All command functions are invoked with ``session`` as its 8 # first argument. Useful session attributes include: 9 # logger: chimerax.core.logger.Logger instance 10 # models: chimerax.core.models.Models instance 11 session.logger.info("Hello world!") 12 13# CmdDesc contains the command description. For the 14# "hello" command, we expect no arguments. 15hello_world_desc = CmdDesc()
To implement the
hello command, two components are needed:
a function that prints
Hello world! to the ChimeraX log,
and a description to register so that ChimeraX knows how to
parse the typed command text and call the function with the
In this simple example,
hello_world is the name of the function
hello_world_desc is the description for the command.
(Note that the function and description names need not match
the command name.)
hello_world_desc, the command description, is an
arguments are passed to the constructor, meaning the
user should not type anything after the command name.
If additional text is entered after the command, ChimeraX will flag
that as an error and display an error message without invoking
If the command is entered correctly, ChimeraX calls the
hello_world function with a single argument,
which provides access to session data such as the open models
and current selection. For this example,
the session logger, an instance of
to display the informational message “Hello world!” The message
is displayed in the log window when the ChimeraX graphical
interface is displayed; otherwise, it is printed to the console.
Later tutorials will discuss how to use the command description to inform ChimeraX how to convert input text to Python values and map them to arguments when calling the command-processing function.
Building and Testing Bundles¶
To build a bundle, start ChimeraX and execute the command:
devel build PATH_TO_SOURCE_CODE_FOLDER
Python source code and other resource files are copied
build sub-folder below the source code
folder. C/C++ source files, if any, are compiled and
also copied into the
The files in
build are then assembled into a
Python wheel in the
The file with the
.whl extension in the
folder is the ChimeraX bundle.
To test the bundle, execute the ChimeraX command:
devel install PATH_TO_SOURCE_CODE_FOLDER
This will build the bundle, if necessary, and install the bundle in ChimeraX. Bundle functionality should be available immediately.
To remove temporary files created while building the bundle, execute the ChimeraX command:
devel clean PATH_TO_SOURCE_CODE_FOLDER
Some files, such as the bundle itself, may still remain and need to be removed manually.
Building bundles as part of a batch process is straightforward, as these ChimeraX commands may be invoked directly by using commands such as:
ChimeraX --nogui --exit --cmd 'devel install PATH_TO_SOURCE_CODE_FOLDER exit true'
This example executes the
devel install command without
displaying a graphics window (
--nogui) and exits immediately
after installation (
exit true). The initial
flag guarantees that ChimeraX will exit even if installation
fails for some reason.
With ChimeraX bundles being packaged as standard Python
wheel-format files, they can be distributed as plain files
and installed using the ChimeraX
command. Thus, electronic mail, web sites and file
sharing services can all be used to distribute ChimeraX
Private distributions are most useful during bundle development, when circulation may be limited to testers. When bundles are ready for public release, they can be published on the ChimeraX Toolshed, which is designed to help developers by eliminating the need for custom distribution channels, and to aid users by providing a central repository where bundles with a variety of different functionality may be found.
Customizable information for each bundle on the toolshed includes its description, screen captures, authors, citation instructions and license terms. Automatically maintained information includes release history and download statistics.
To submit a bundle for publication on the toolshed,
you must first sign in. Currently, only Google
sign in is supported. Once signed in, use the
Submit a Bundle link at the top of the page
to initiate submission, and follow the instructions.
The first time a bundle is submitted to the toolshed,
it is held for inspection by the ChimeraX team, which
may contact the authors for more information.
Once approved, all subsequent submissions of new
versions of the bundle are posted immediately on the site.
Bundle Example: Hello World (current topic)
Bundle Example: Add a Command (next topic)