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.