Bundle Example: Save a New File Format¶
This example describes how to create a ChimeraX bundle that allows ChimeraX to open and save data files in XYZ format, which is a simple format containing only information about atomic types and coordinates. The example files are almost identical to those from Bundle Example: Read a New File Format, with a few additions for saving XYZ files.
Code for both reading and writing a new format is typically supplied in the same bundle. However, an alternative is to have separate bundles for reading and writing, by making one bundle dependent on the other. For example, the base bundle can define the data format and handle open requests; the dependent bundle can then handle only save requests (using the same data format definition from the base bundle).
The steps in implementing the bundle are:
Create a
bundle_info.xmlcontaining information about the bundle,Create a Python package that interfaces with ChimeraX and implements the file-reading 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 tut_save. 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.
Sample Files¶
The files in the tut_save folder are:
tut_save- bundle folderbundle_info.xml- bundle information read by ChimeraXsrc- source code to Python package for bundle__init__.py- package initializer and interface to ChimeraXio.py- source code to read and save XYZ format files
The file contents are shown below.
bundle_info.xml¶
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. The
bundle_info.xml in this example is similar to the one
from the Bundle Example: Add a Tool example with changes highlighted.
For explanations of the unhighlighted sections, please
see Bundle Example: Hello World, Bundle Example: Add a Command,
Bundle Example: Add a Tool, and Bundle Example: Read a New File Format.
The BundleInfo, Synopsis and Description tags are
changed to reflect the new bundle name and documentation
(lines 8-10 and 17-23).
The Providers sections on lines 36 through 48 use the
Manager/Provider protocol to inform
the “data formats” manager about the XYZ format, and the “open command”
and “save command” managers, respectively, that this bundle can open
and save XYZ files,
The attributes usable with the “data formats” manager are described in
detail in Defining a File/Data Format. Note that most formats have a longer
official name than “XYZ” and therefore most formats will also specify
nicknames and synopsis attributes, whereas they are unneeded
in this example.
The “open command” attributes are described in detail in
Opening Files.
Likewise, the “save command” attributes are described in detail in
Saving Files.
It is typical that the only attribute specified is name.
src¶
src is the folder containing the source code for the
Python package that implements the bundle functionality.
The ChimeraX devel command, used for building and
installing bundles, automatically includes all .py
files in src as part of the bundle. (Additional
files may also be included using bundle information tags
such as DataFiles as shown in Bundle Example: Add a Tool.)
The only required file in src is __init__.py.
Other .py files are typically arranged to implement
different types of functionality. For example, cmd.py
is used for command-line commands; tool.py or gui.py
for graphical interfaces; io.py for reading and saving
files, etc.
src/__init__.py¶
As described in Bundle Example: Hello World, __init__.py contains
the initialization code that defines the bundle_api object
that ChimeraX needs in order to invoke bundle functionality.
ChimeraX expects bundle_api class to be derived from
chimerax.core.toolshed.BundleAPI with methods
overridden for registering commands, tools, etc.
The run_provider() method is called by a ChimeraX manager
when it needs additional information from a provider or it needs a
provider to execute a task.
The session argument is a Session instance,
the name argument is the same as the name attribute in your Provider
tag, and the mgr argument is the manager instance.
These arguments can be used to decide what to do when your bundle offers
several Provider tags, such as in this example.
The “data formats” manager never calls run_provider(), so we only
need to know if it’s the “open command” or “save command” manager calling
this method.
This “open command” manager is also session.open_command (and “save command”
is session.save_command), so we use the test on line 36 to decide.
The information needed by the “open command” manager is returned by the code on lines 37-44 and is described in detail in Bundle Example: Read a New File Format.
When called by the “save command” manager, run_provider() must return
an instance of a subclass of chimerax.save_command.SaverInfo.
The methods of the class are thoroughly documented if you click the preceding
link, but briefly:
The
save()method is called to actually save the file (and has no return value). The method’s path is the full path name of the file to save.If there are format-specific keyword arguments that the
savecommand should handle, then asave_args()property should be implemented, which returns a dictionary mapping Python keyword names to Annotation subclasses. Such keywords will be passed to yoursave()method.If your underlying file-writing function uses
open_output()to open the path, then compression implied by the file name (e.g. a additional .gz suffix) will be handled automatically.In the rare case where you save a file type that ChimeraX knows how to open but would be inappriate to open for some reason, set
in_file_historytoFalseto exclude it from the file history listing.
src/io.py¶
The open_xyz and _read_block functions are described in
detail in Bundle Example: Read a New File Format.
The save_xyz function performs the following steps:
open the output file for writing using the ChimeraX function
open_output()(lines 112-116),if the structures keyword was not given, include all atomic structures for saving (lines 118-121),
initialize the total atom count (line 122),
loop through the structures to save (line 125) and:
get the lists of atoms and coordinates for the structure. (lines 129-130),
print the first two lines (number of atoms and comment) for the structure to the file (lines 132-135),
print one line per atom using the atom and coordinates lists, and
update total atom count (lines 136-141).
close the output file (line 142)
finally, log a status message to let the user know what was written (lines 144-146).
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
into a build sub-folder below the source code
folder. C/C++ source files, if any, are compiled and
also copied into the build folder.
The files in build are then assembled into a
Python wheel in the dist sub-folder.
The file with the .whl extension in the dist
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 --exit
flag guarantees that ChimeraX will exit even if installation
fails for some reason.
Distributing Bundles¶
With ChimeraX bundles being packaged as standard Python
wheel-format files, they can be distributed as plain files
and installed using the ChimeraX toolshed install
command. Thus, electronic mail, web sites and file
sharing services can all be used to distribute ChimeraX
bundles.
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.
What’s Next¶
Bundle Example: Read a New File Format (previous topic)
Bundle Example: Save a New File Format (current topic)
Bundle Example: Fetch from Network Database (next topic)