Python Retrosynthesis with RENKIN
If you're looking for an open-source Python library for computer-aided synthesis planning (CASP) that doesn't require RDKit or a C/C++ toolchain, RENKIN ships as a pip-installable wheel with the search engine, template set, and building-block database compiled in.
Install
No RDKit, no Boost, no C/C++ compiler needed at install time — RENKIN's
chemistry layer (chematic) and search engine
are both pure Rust, compiled ahead of time into the wheel.
A Working Example
"""RENKIN Python quickstart. Runs as part of CI so this example can never
silently drift from the real API (see .github/workflows/ci.yml)."""
import json
import renkin
result = json.loads(
renkin.find_routes(
target="CC(=O)Oc1ccccc1C(=O)O", # Aspirin
depth=5,
max_routes=3,
)
)
print(f"Routes found: {result['routes_found']}")
for route in result["routes"]:
print(f"Route (depth {route['depth']}):")
for step in route["steps"]:
print(f" {step['target']} -> {' + '.join(step['precursors'])}")
print(f" via {step['rule']}")
find_routes always returns a JSON string, not a dict — call
json.loads() on it. Full parameter list and return shape:
Python API reference.
Custom Building Blocks
With no building_blocks argument, RENKIN searches against data/building_blocks.smi
(402 unique compounds) if that path resolves relative to your current working
directory — in practice, only when running from a checkout of this repo. A
pip install renkin wheel does not bundle that file, so a plain pip install
run from anywhere else silently falls back to a smaller, compiled-in
152-compound set instead. Don't rely on either default having a specific
compound — supply your own stock explicitly:
import renkin, json
my_stock = ["CC(=O)O", "Oc1ccccc1", "c1ccccc1", "Brc1ccccc1", "OB(O)c1ccccc1"]
result = json.loads(renkin.find_routes(
target="c1ccc(-c2ccccc2)cc1",
building_blocks=my_stock,
depth=3,
))
Any SMILES that fails to parse is silently skipped, not an error — it just can't match as a leaf building block.
Extracted Templates
The built-in rule set is 22 hand-crafted, human-readable disconnections (ester cleavage, Suzuki, Heck, and so on). For broader reaction coverage, load additional SMIRKS templates auto-extracted from USPTO-50k/MIT via rdchiral:
result = json.loads(renkin.find_routes(
target="CC(=O)Oc1ccccc1C(=O)O",
templates_path="data/templates_extracted_5000.smi",
depth=5,
))
Each extracted template gets a stable template_id
(smirks-sha256:<hex>) derived from the SMIRKS itself, independent of file
order or position — unlike the display name (extracted_0, extracted_1, ...),
which shifts if the file is re-sorted or re-extracted.
Evidence Metadata (Conditions, Yields, References)
You can attach curated external evidence — reported conditions, yields, DOIs,
patents, known side-reaction warnings — to a specific template, keyed by its
template_id:
result = json.loads(renkin.find_routes(
target="CC(=O)Oc1ccccc1C(=O)O",
templates_path="data/templates_extracted_5000.smi",
template_metadata_path="sidecar.json",
depth=5,
))
for route in result["routes"]:
for step in route["steps"]:
if "evidence" in step:
print(step["template_id"], step["evidence"])
Steps whose template has no matching sidecar entry simply have no evidence
key — nothing is fabricated. See the Reaction Evidence Metadata
guide for the sidecar format and what evidence is
(and isn't).
Reading the Result
Real output for aspirin at depth=1 (hand-crafted rules only, one route shown):
{
"depth": 1,
"score": 1.099087,
"confidence": 1.0,
"success_probability": 1.0,
"route_cost": 8.298266666666667,
"building_blocks": ["OC(=O)C", "c1cccc(c1O)C(O)=O"],
"steps": [
{
"target": "OC(=O)c1ccccc1OC(=O)C",
"rule": "ester_cleavage",
"template_id": "rule:ester_cleavage",
"precursors": ["OC(=O)C", "c1cccc(c1O)C(O)=O"],
"step_confidence": 1.0,
"atom_economy": 90.90950376941474,
"atom_economy_raw_percent": 90.90950376941474,
"atom_economy_status": "normal",
"reaction_family": "esterification",
"conditions": {"catalyst": "NaOH or LiOH (2 eq)", "solvent": "THF/H₂O (2:1)", "temperature": "rt → 60 °C"},
"procedure_hint": "Dissolve in THF/H₂O, add NaOH (2 eq), stir at 60 °C, acidify to pH 2.",
"metadata_source": "handcrafted_default",
"metadata_scope": "reaction_family"
# evidence appears only when a --template-metadata sidecar matches this template_id
}
]
}
step_confidence/success_probability are template-frequency-derived
search-ranking scores (here 1.0 because, with only hand-crafted rules loaded,
every rule has equal weight) — not a measured or predicted experimental
yield. conditions/procedure_hint are rule-author-supplied defaults for
hand-crafted rules (metadata_source: "handcrafted_default"), not a literature
citation — see Reaction Evidence Metadata for the
distinction and how to attach real cited evidence.
Current Limitations
- The default stock (402 compounds when running from a repo checkout, 152 otherwise — see Building Blocks) and 27 hand-crafted rules cover common pharmaceutical disconnections well, but broader reaction space needs the larger extracted-template files or your own stock.
- No literature/patent auto-search, no automatic side-reaction prediction, no yield prediction — see Reaction Evidence Metadata for exactly what curated evidence is and isn't.
- Historical benchmark numbers on this repo predate a validator-accuracy fix and are invalidated — see the frozen Benchmark page for the corrected historical baseline, or the Open-Source Retrosynthesis Comparison guide for current, matched-condition results, before citing a success rate.
Next Steps
- Python API reference — full parameter list,
predict_forward,validate_forward - Reaction Evidence Metadata — conditions, yields, references, warnings
- Rust API / WASM API — if you need the engine outside Python