ccd2rdmol
A lightweight Python library and CLI tool for converting PDB Chemical Component Dictionary (CCD) files to RDKit molecule objects.
This project is a simplified implementation inspired by pdbeccdutils, focusing solely on CCD to RDKit conversion with 3D conformer support.
Features
- Fast CIF parsing using gemmi
- Conversion to RDKit molecule objects
- Support for both Ideal and Model 3D conformers
- Automatic metal bond to dative bond conversion
- Stereochemistry assignment from 3D coordinates
- Deuterium isotope handling
- Degenerate conformer detection and rejection
- CLI tool with rich output
Installation
# Library only
uv add ccd2rdmol
# With CLI support
uv add ccd2rdmol[cli]
Or with pip:
pip install ccd2rdmol
pip install ccd2rdmol[cli]
For development:
git clone https://github.com/N283T/ccd2rdmol.git
cd ccd2rdmol
uv sync # CLI is included in dev dependencies
Quick Start
from ccd2rdmol import read_ccd_file
result = read_ccd_file("ATP.cif")
print(f"Atoms: {result.mol.GetNumAtoms()}")
print(f"Sanitized: {result.sanitized}")
Usage
Reading from a CIF File
from ccd2rdmol import read_ccd_file
# Default: sanitize, add conformers, remove hydrogens
result = read_ccd_file("ATP.cif")
mol = result.mol
print(f"Atoms: {mol.GetNumAtoms()}")
print(f"Bonds: {mol.GetNumBonds()}")
print(f"Conformers: {mol.GetNumConformers()}") # 2 (IDEAL + MODEL)
print(f"Sanitized: {result.sanitized}")
# With options
result = read_ccd_file(
"ATP.cif",
sanitize_mol=True, # Sanitize molecule (default: True)
add_conformers=True, # Add 3D conformers (default: True)
remove_hydrogens=True, # Remove hydrogens (default: True)
)
Reading from a gemmi CIF Block
import gemmi
from ccd2rdmol import read_ccd_block
doc = gemmi.cif.read("components.cif")
for block in doc:
result = read_ccd_block(block)
print(f"{block.name}: {result.mol.GetNumAtoms()} atoms")
Low-Level API: chemcomp_to_mol
import gemmi
from ccd2rdmol import chemcomp_to_mol
doc = gemmi.cif.read("ATP.cif")
block = doc.sole_block()
cc = gemmi.make_chemcomp_from_block(block)
result = chemcomp_to_mol(
cc, block,
sanitize_mol=False, # Skip sanitization
add_conformers=True,
remove_hydrogens=False, # Keep all hydrogens
)
Generating SMILES and InChI
from rdkit import Chem
from rdkit.Chem.inchi import MolToInchi
from ccd2rdmol import read_ccd_file
result = read_ccd_file("ATP.cif")
smiles = Chem.MolToSmiles(result.mol)
inchi = MolToInchi(result.mol)
print(f"SMILES: {smiles}")
print(f"InChI: {inchi}")
Accessing Conformer Coordinates
from ccd2rdmol import read_ccd_file
result = read_ccd_file("ATP.cif", add_conformers=True)
mol = result.mol
for conf in mol.GetConformers():
name = conf.GetProp("name") # "IDEAL" or "MODEL"
print(f"\n{name} conformer:")
for i in range(mol.GetNumAtoms()):
pos = conf.GetAtomPosition(i)
atom = mol.GetAtomWithIdx(i)
print(f" {atom.GetSymbol()} ({pos.x:.3f}, {pos.y:.3f}, {pos.z:.3f})")
Handling Conversion Errors
from ccd2rdmol import read_ccd_file
result = read_ccd_file("complex_molecule.cif")
if result.errors:
print("Errors:", result.errors)
if result.warnings:
print("Warnings:", result.warnings)
if not result.sanitized:
print("Sanitization failed — molecule may have valence issues")
API Reference
Functions
read_ccd_file(path, *, sanitize_mol=True, add_conformers=True, remove_hydrogens=True) → ConversionResult
Read a CCD CIF file and convert to RDKit molecule.
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
str |
— | Path to CIF file |
sanitize_mol |
bool |
True |
Sanitize the molecule (fix valence, kekulize) |
add_conformers |
bool |
True |
Add IDEAL and MODEL 3D conformers |
remove_hydrogens |
bool |
True |
Remove hydrogen atoms from the molecule |
Raises FileNotFoundError if file does not exist.
read_ccd_block(cif_block, *, sanitize_mol=True, add_conformers=True, remove_hydrogens=True) → ConversionResult
Convert a gemmi.cif.Block to RDKit molecule. Same parameters as read_ccd_file except takes a pre-parsed CIF block.
chemcomp_to_mol(cc, cif_block, *, sanitize_mol=True, add_conformers=True, remove_hydrogens=True) → ConversionResult
Convert a gemmi.ChemComp and gemmi.cif.Block to RDKit molecule. Lowest-level API for maximum control.
Data Classes
ConversionResult
Frozen dataclass returned by all conversion functions.
| Field | Type | Description |
|---|---|---|
mol |
Chem.Mol |
RDKit molecule object |
sanitized |
bool |
Whether sanitization succeeded |
errors |
list[str] |
Errors encountered during conversion |
warnings |
list[str] |
Warnings (e.g., missing conformer data) |
SanitizationResult
Frozen dataclass returned by sanitize().
| Field | Type | Description |
|---|---|---|
mol |
Chem.Mol |
Sanitized molecule (always a copy) |
success |
bool |
Whether sanitization succeeded |
How It Works
The conversion pipeline:
- Parse CIF — gemmi reads the CIF file and creates a
ChemComp(atoms, bonds, charges) and acif.Block(coordinate data) - Build molecule — Atoms are added to an RDKit
RWMolwith element types, charges, and isotope labels (Deuterium → isotope 2). Bonds are mapped from gemmi bond types to RDKit bond types viaBOND_TYPE_MAP - Set hydrogen flags — Atoms without explicit hydrogen neighbors are flagged
NoImplicit=Trueto prevent RDKit from adding implicit hydrogens - Add conformers — IDEAL and MODEL 3D coordinates are read from the CIF coordinate columns. Conformers with all-missing coordinates or degenerate positions (>1 atom at origin) are rejected
- Sanitize — The sanitizer fixes valence errors caused by metal-ligand bonds by converting them to dative bonds. Uses
Chem.DetectChemistryProblems()to identify problematic atoms and iteratively fixes them (up to 11 attempts). The original molecule is never modified - Assign stereochemistry —
AssignStereochemistryFrom3Dis called using the IDEAL conformer (preferred) or MODEL conformer - Remove hydrogens — Optionally strips hydrogen atoms from the final molecule
Comparison with pdbeccdutils
| ccd2rdmol | pdbeccdutils | |
|---|---|---|
| Focus | CCD → RDKit conversion only | Full CCD processing toolkit |
| Dependencies | gemmi + rdkit | gemmi + rdkit + scipy + numpy + ... |
| Scope | Single molecules from CIF | Depictions, scaffolds, fragments, PDB integration |
| Install size | Minimal | ~50+ transitive dependencies |
| Use case | "I just need an RDKit Mol from a CCD entry" | Full cheminformatics pipeline |
If you only need to convert CCD entries to RDKit molecules, ccd2rdmol provides a simpler, lighter alternative.
CLI
Note: CLI requires extra dependencies. Install with
pip install ccd2rdmol[cli]
# Output SMILES to stdout
ccd2rdmol convert ATP.cif
# Write to MOL file
ccd2rdmol convert ATP.cif -o ATP.mol
# Write to SDF format
ccd2rdmol convert ATP.cif -o ATP.sdf
# Output InChI
ccd2rdmol convert ATP.cif -f inchi
# Keep hydrogen atoms
ccd2rdmol convert ATP.cif --keep-hydrogens
# Show verbose information
ccd2rdmol convert ATP.cif -v
# Show molecule information only
ccd2rdmol info ATP.cif
CLI Options
ccd2rdmol convert [OPTIONS] INPUT_FILE
Arguments:
INPUT_FILE Input CCD CIF file path [required]
Options:
-o, --output PATH Output file path (.mol, .sdf)
-f, --format TEXT Output format (mol, sdf, smiles, inchi)
--no-sanitize Skip sanitization step
--no-conformers Skip adding 3D conformers
-H, --keep-hydrogens Keep hydrogen atoms
-v, --verbose Show detailed information
--help Show help message
Development
This project uses poethepoet as a task runner.
# Install dev dependencies
uv sync
# Format code (ruff format)
uv run poe format
# Lint (ruff check)
uv run poe lint
# Lint and auto-fix
uv run poe fix
# Type check (ty)
uv run poe check
# Run tests
uv run poe test
# Run tests with coverage
uv run poe test-cov
# Multi-version testing with nox (3.10, 3.11, 3.12, 3.13, 3.14)
uv run poe nox
# Run all checks (format, lint, check, test)
uv run poe all
# Clean cache files
uv run poe clean
Acknowledgments
This project is inspired by and built upon concepts from pdbeccdutils by PDBe (Protein Data Bank in Europe). Test data files are derived from the pdbeccdutils test suite.
We thank the PDBe team for their excellent work on chemical component processing tools.
License
MIT License
Test data files in tests/data/ are from pdbeccdutils (Apache-2.0 License).
Metadata
Release files for ccd2rdmol 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ccd2rdmol-0.2.2.tar.gz | 163.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ccd2rdmol-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 175.8 kB
Release files / ccd2rdmol-0.2.2.tar.gz
| Download URL | ccd2rdmol-0.2.2.tar.gz |
|---|---|
| Size | 163.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
08b0219402d6c53321929d5b1025a59260063b9efe30c6f945fa4e73ba449198
|
|
BLAKE2b-256 checksum How to use checksums |
39fa1b18191326c48811ca01acb59e055d74ef0cbddb99e3753c5187a5c5ba56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 11, 2026.
Transparency logRelease files / ccd2rdmol-0.2.2-py3-none-any.whl
| Download URL | ccd2rdmol-0.2.2-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75100d5f523ac3a77bb29fa4c85e52f2ba5aac99d2da70b12477e8e503398a7f
|
|
BLAKE2b-256 checksum How to use checksums |
b0fe485b7d5593a20a451fe4f628d19195d3baae0cdb71c369b2ac211c78e367
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 11, 2026.
Transparency logSecurity for ccd2rdmol 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ccd2rdmol-0.2.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.