OxMol: Rust/Python Bindings for ChemCore
Python is the most popular orchestration language in scientific computing. Across a variety of fields, Python provides high-level interfaces to fast code written in other languages. A previous article introduced ChemCore, a new cheminformatics library written in Rust. This article moves the idea another step forward by introducing OxMol, Python bindings for ChemCore.
Installation
The OxMol documentation describes two installation methods. The simplest is just a one-liner:
pip install --index-url https://test.pypi.org/simple/ oxmol
On my macOS Mojave system, a slightly modified version of this command worked:
pip3 install --index-url https://test.pypi.org/simple/ oxmol
Hello, Ethane
OxMol closely follows the ChemCore API. Molecule construction follows the same pattern you'd find in Rust.
from oxmol import AtomSpec, BondSpec, Molecule
atoms = [ AtomSpec('C', 3), AtomSpec('C', 3) ]
bonds = [ BondSpec(0, 1, 1) ]
mol = Molecule(atoms, bonds)
# exercise the full Molecule interface
mol.is_empty() # False
mol.order() # 2
mol.size() # 1
mol.nodes # [0, 1]
mol.has_node(0) # True
mol.neighbors(0) # [1]
mol.degree(0) # 1
mol.edges # [(0, 1)]
mol.has_edge(0, 1) # True
mol.element(0) # PyElement::C
mol.isotope(0) # nil
mol.electrons(0) # 0
mol.hydrogens(0) # 3
mol.atom_parity(0) # nil
mol.bond_order(0, 1) # PyBondOrder::Single
mol.bond_parity(0, 1) # nil
About OxMol
OxMol was created by Travis Hesketh, a postgraduate researcher at the University of Strathclyde. The package currently supports the construction of Molecule
instances conforming to the Minimal Molecule API. The README notes these future directions:
- SMILES read/write
- substructure search
- coordinate representation and embedding
- descriptor calculation
ChemCore's top priority is a complete SMILES reader. So that functionality is likely to appear in OxMol first.
PyO3
OxMol uses PyO3, which provides two-way bindings between Python and Rust. The approach is similar to pybind for C++/Python interop. The main reason to use PyO3 is all of the work it does for you. A suite of procedural macros dynamically generates low-level glue code.
Even so, OxMol requires considerable glue code of its own. For example, see DefaultMolecule
. This wrapper exposes a Rust interface, but accepting and returning PyO3-specific types. In a nutshell, the Molecule
interface is re-implemented using a delegate implementation provided by ChemCore. Fortunately, the interface was designed with ease of implementation in mind. Even so, it might be possible to take the automation one step further here.
More Python-Rust Interop
PyO3 is but one option for Rust/Python interop. Others include:
- RustPy. Bidirectional mappings using FFI.
- rust-cpython. The project from which PyO3 was forked.
- Calling Rust in Python. A soup-to-nuts exploration of wrapping Rust with Python from scratch.
- Milksnake. Builds "regular native libraries that are then loaded with CFFI at runtime." Currently inactive.
Conclusion
OxMol provides Python wrappers to the new Rust cheminformatics library ChemCore. The project's feature set is restricted by the currently limited feature set of the underlying Rust library. If you're interested in the combination of cheminformatics, Rust, and Python, it's a project worth checking out.