
Medchem
- 34 installs
- 16 repo stars
- Updated November 20, 2025
- jackspace/claudeskillz
Apply drug-likeness rules (Lipinski, Veber), PAINS filters, and structural alerts to triage and prioritize compound libraries.
About
A Python library that applies medicinal-chemistry rules, structural alerts, and complexity metrics to filter molecules. A developer uses it to triage and prioritize compounds in drug-discovery workflows.
- Rule of Five, Veber, CNS, leadlike, and PAINS filters
- Structural alerts and molecular complexity metrics
Medchem by the numbers
- 34 all-time installs (skills.sh)
- Ranked #1,081 of 2,065 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/jackspace/claudeskillz --skill medchemAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 34 |
|---|---|
| repo stars | ★ 16 |
| Last updated | November 20, 2025 |
| Repository | jackspace/claudeskillz ↗ |
What it does
Apply drug-likeness rules (Lipinski, Veber), PAINS filters, and structural alerts to triage and prioritize compound libraries.
Files
Medchem
Overview
Medchem is a Python library for molecular filtering and prioritization in drug discovery workflows. Apply hundreds of well-established and novel molecular filters, structural alerts, and medicinal chemistry rules to efficiently triage and prioritize compound libraries at scale. Rules and filters are context-specific—use as guidelines combined with domain expertise.
When to Use This Skill
This skill should be used when:
- Applying drug-likeness rules (Lipinski, Veber, etc.) to compound libraries
- Filtering molecules by structural alerts or PAINS patterns
- Prioritizing compounds for lead optimization
- Assessing compound quality and medicinal chemistry properties
- Detecting reactive or problematic functional groups
- Calculating molecular complexity metrics
Installation
Install medchem via conda or pip:
# Via conda
micromamba install -c conda-forge medchem
# Via pip
pip install medchemCore Capabilities
1. Medicinal Chemistry Rules
Apply established drug-likeness rules to molecules using the medchem.rules module.
Available Rules:
- Rule of Five (Lipinski)
- Rule of Oprea
- Rule of CNS
- Rule of leadlike (soft and strict)
- Rule of three
- Rule of Reos
- Rule of drug
- Rule of Veber
- Golden triangle
- PAINS filters
Single Rule Application:
import medchem as mc
# Apply Rule of Five to a SMILES string
smiles = "CC(=O)OC1=CC=CC=C1C(=O)O" # Aspirin
passes = mc.rules.basic_rules.rule_of_five(smiles)
# Returns: True
# Check specific rules
passes_oprea = mc.rules.basic_rules.rule_of_oprea(smiles)
passes_cns = mc.rules.basic_rules.rule_of_cns(smiles)Multiple Rules with RuleFilters:
import datamol as dm
import medchem as mc
# Load molecules
mols = [dm.to_mol(smiles) for smiles in smiles_list]
# Create filter with multiple rules
rfilter = mc.rules.RuleFilters(
rule_list=[
"rule_of_five",
"rule_of_oprea",
"rule_of_cns",
"rule_of_leadlike_soft"
]
)
# Apply filters with parallelization
results = rfilter(
mols=mols,
n_jobs=-1, # Use all CPU cores
progress=True
)Result Format: Results are returned as dictionaries with pass/fail status and detailed information for each rule.
2. Structural Alert Filters
Detect potentially problematic structural patterns using the medchem.structural module.
Available Filters:
1. Common Alerts - General structural alerts derived from ChEMBL curation and literature 2. NIBR Filters - Novartis Institutes for BioMedical Research filter set 3. Lilly Demerits - Eli Lilly's demerit-based system (275 rules, molecules rejected at >100 demerits)
Common Alerts:
import medchem as mc
# Create filter
alert_filter = mc.structural.CommonAlertsFilters()
# Check single molecule
mol = dm.to_mol("c1ccccc1")
has_alerts, details = alert_filter.check_mol(mol)
# Batch filtering with parallelization
results = alert_filter(
mols=mol_list,
n_jobs=-1,
progress=True
)NIBR Filters:
import medchem as mc
# Apply NIBR filters
nibr_filter = mc.structural.NIBRFilters()
results = nibr_filter(mols=mol_list, n_jobs=-1)Lilly Demerits:
import medchem as mc
# Calculate Lilly demerits
lilly = mc.structural.LillyDemeritsFilters()
results = lilly(mols=mol_list, n_jobs=-1)
# Each result includes demerit score and whether it passes (≤100 demerits)3. Functional API for High-Level Operations
The medchem.functional module provides convenient functions for common workflows.
Quick Filtering:
import medchem as mc
# Apply NIBR filters to a list
filter_ok = mc.functional.nibr_filter(
mols=mol_list,
n_jobs=-1
)
# Apply common alerts
alert_results = mc.functional.common_alerts_filter(
mols=mol_list,
n_jobs=-1
)4. Chemical Groups Detection
Identify specific chemical groups and functional groups using medchem.groups.
Available Groups:
- Hinge binders
- Phosphate binders
- Michael acceptors
- Reactive groups
- Custom SMARTS patterns
Usage:
import medchem as mc
# Create group detector
group = mc.groups.ChemicalGroup(groups=["hinge_binders"])
# Check for matches
has_matches = group.has_match(mol_list)
# Get detailed match information
matches = group.get_matches(mol)5. Named Catalogs
Access curated collections of chemical structures through medchem.catalogs.
Available Catalogs:
- Functional groups
- Protecting groups
- Common reagents
- Standard fragments
Usage:
import medchem as mc
# Access named catalogs
catalogs = mc.catalogs.NamedCatalogs
# Use catalog for matching
catalog = catalogs.get("functional_groups")
matches = catalog.get_matches(mol)6. Molecular Complexity
Calculate complexity metrics that approximate synthetic accessibility using medchem.complexity.
Common Metrics:
- Bertz complexity
- Whitlock complexity
- Barone complexity
Usage:
import medchem as mc
# Calculate complexity
complexity_score = mc.complexity.calculate_complexity(mol)
# Filter by complexity threshold
complex_filter = mc.complexity.ComplexityFilter(max_complexity=500)
results = complex_filter(mols=mol_list)7. Constraints Filtering
Apply custom property-based constraints using medchem.constraints.
Example Constraints:
- Molecular weight ranges
- LogP bounds
- TPSA limits
- Rotatable bond counts
Usage:
import medchem as mc
# Define constraints
constraints = mc.constraints.Constraints(
mw_range=(200, 500),
logp_range=(-2, 5),
tpsa_max=140,
rotatable_bonds_max=10
)
# Apply constraints
results = constraints(mols=mol_list, n_jobs=-1)8. Medchem Query Language
Use a specialized query language for complex filtering criteria.
Query Examples:
# Molecules passing Ro5 AND not having common alerts
"rule_of_five AND NOT common_alerts"
# CNS-like molecules with low complexity
"rule_of_cns AND complexity < 400"
# Leadlike molecules without Lilly demerits
"rule_of_leadlike AND lilly_demerits == 0"Usage:
import medchem as mc
# Parse and apply query
query = mc.query.parse("rule_of_five AND NOT common_alerts")
results = query.apply(mols=mol_list, n_jobs=-1)Workflow Patterns
Pattern 1: Initial Triage of Compound Library
Filter a large compound collection to identify drug-like candidates.
import datamol as dm
import medchem as mc
import pandas as pd
# Load compound library
df = pd.read_csv("compounds.csv")
mols = [dm.to_mol(smi) for smi in df["smiles"]]
# Apply primary filters
rule_filter = mc.rules.RuleFilters(rule_list=["rule_of_five", "rule_of_veber"])
rule_results = rule_filter(mols=mols, n_jobs=-1, progress=True)
# Apply structural alerts
alert_filter = mc.structural.CommonAlertsFilters()
alert_results = alert_filter(mols=mols, n_jobs=-1, progress=True)
# Combine results
df["passes_rules"] = rule_results["pass"]
df["has_alerts"] = alert_results["has_alerts"]
df["drug_like"] = df["passes_rules"] & ~df["has_alerts"]
# Save filtered compounds
filtered_df = df[df["drug_like"]]
filtered_df.to_csv("filtered_compounds.csv", index=False)Pattern 2: Lead Optimization Filtering
Apply stricter criteria during lead optimization.
import medchem as mc
# Create comprehensive filter
filters = {
"rules": mc.rules.RuleFilters(rule_list=["rule_of_leadlike_strict"]),
"alerts": mc.structural.NIBRFilters(),
"lilly": mc.structural.LillyDemeritsFilters(),
"complexity": mc.complexity.ComplexityFilter(max_complexity=400)
}
# Apply all filters
results = {}
for name, filt in filters.items():
results[name] = filt(mols=candidate_mols, n_jobs=-1)
# Identify compounds passing all filters
passes_all = all(r["pass"] for r in results.values())Pattern 3: Identify Specific Chemical Groups
Find molecules containing specific functional groups or scaffolds.
import medchem as mc
# Create group detector for multiple groups
group_detector = mc.groups.ChemicalGroup(
groups=["hinge_binders", "phosphate_binders"]
)
# Screen library
matches = group_detector.get_all_matches(mol_list)
# Filter molecules with desired groups
mol_with_groups = [mol for mol, match in zip(mol_list, matches) if match]Best Practices
1. Context Matters: Don't blindly apply filters. Understand the biological target and chemical space.
2. Combine Multiple Filters: Use rules, structural alerts, and domain knowledge together for better decisions.
3. Use Parallelization: For large datasets (>1000 molecules), always use n_jobs=-1 for parallel processing.
4. Iterative Refinement: Start with broad filters (Ro5), then apply more specific criteria (CNS, leadlike) as needed.
5. Document Filtering Decisions: Track which molecules were filtered out and why for reproducibility.
6. Validate Results: Remember that marketed drugs often fail standard filters—use these as guidelines, not absolute rules.
7. Consider Prodrugs: Molecules designed as prodrugs may intentionally violate standard medicinal chemistry rules.
Resources
references/api_guide.md
Comprehensive API reference covering all medchem modules with detailed function signatures, parameters, and return types.
references/rules_catalog.md
Complete catalog of available rules, filters, and alerts with descriptions, thresholds, and literature references.
scripts/filter_molecules.py
Production-ready script for batch filtering workflows. Supports multiple input formats (CSV, SDF, SMILES), configurable filter combinations, and detailed reporting.
Usage:
python scripts/filter_molecules.py input.csv --rules rule_of_five,rule_of_cns --alerts nibr --output filtered.csvDocumentation
Official documentation: https://medchem-docs.datamol.io/ GitHub repository: https://github.com/datamol-io/medchem
{
"description": "\"Medicinal chemistry filters. Apply drug-likeness rules (Lipinski, Veber), PAINS filters, structural alerts, complexity metrics, for compound prioritization and library filtering.\"",
"references": {
"files": [
"references/api_guide.md",
"references/rules_catalog.md"
]
},
"content": "Install medchem via conda or pip:\r\n\r\n```bash\r\nmicromamba install -c conda-forge medchem\r\n\r\n\r\n### 1. Medicinal Chemistry Rules\r\n\r\nApply established drug-likeness rules to molecules using the `medchem.rules` module.\r\n\r\n**Available Rules:**\r\n- Rule of Five (Lipinski)\r\n- Rule of Oprea\r\n- Rule of CNS\r\n- Rule of leadlike (soft and strict)\r\n- Rule of three\r\n- Rule of Reos\r\n- Rule of drug\r\n- Rule of Veber\r\n- Golden triangle\r\n- PAINS filters\r\n\r\n**Single Rule Application:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nsmiles = \"CC(=O)OC1=CC=CC=C1C(=O)O\" # Aspirin\r\npasses = mc.rules.basic_rules.rule_of_five(smiles)\r\n\r\npasses_oprea = mc.rules.basic_rules.rule_of_oprea(smiles)\r\npasses_cns = mc.rules.basic_rules.rule_of_cns(smiles)\r\n```\r\n\r\n**Multiple Rules with RuleFilters:**\r\n\r\n```python\r\nimport datamol as dm\r\nimport medchem as mc\r\n\r\nmols = [dm.to_mol(smiles) for smiles in smiles_list]\r\n\r\nrfilter = mc.rules.RuleFilters(\r\n rule_list=[\r\n \"rule_of_five\",\r\n \"rule_of_oprea\",\r\n \"rule_of_cns\",\r\n \"rule_of_leadlike_soft\"\r\n ]\r\n)\r\n\r\nresults = rfilter(\r\n mols=mols,\r\n n_jobs=-1, # Use all CPU cores\r\n progress=True\r\n)\r\n```\r\n\r\n**Result Format:**\r\nResults are returned as dictionaries with pass/fail status and detailed information for each rule.\r\n\r\n### 2. Structural Alert Filters\r\n\r\nDetect potentially problematic structural patterns using the `medchem.structural` module.\r\n\r\n**Available Filters:**\r\n\r\n1. **Common Alerts** - General structural alerts derived from ChEMBL curation and literature\r\n2. **NIBR Filters** - Novartis Institutes for BioMedical Research filter set\r\n3. **Lilly Demerits** - Eli Lilly's demerit-based system (275 rules, molecules rejected at >100 demerits)\r\n\r\n**Common Alerts:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nalert_filter = mc.structural.CommonAlertsFilters()\r\n\r\nmol = dm.to_mol(\"c1ccccc1\")\r\nhas_alerts, details = alert_filter.check_mol(mol)\r\n\r\nresults = alert_filter(\r\n mols=mol_list,\r\n n_jobs=-1,\r\n progress=True\r\n)\r\n```\r\n\r\n**NIBR Filters:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nnibr_filter = mc.structural.NIBRFilters()\r\nresults = nibr_filter(mols=mol_list, n_jobs=-1)\r\n```\r\n\r\n**Lilly Demerits:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nlilly = mc.structural.LillyDemeritsFilters()\r\nresults = lilly(mols=mol_list, n_jobs=-1)\r\n\r\n```\r\n\r\n### 3. Functional API for High-Level Operations\r\n\r\nThe `medchem.functional` module provides convenient functions for common workflows.\r\n\r\n**Quick Filtering:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nfilter_ok = mc.functional.nibr_filter(\r\n mols=mol_list,\r\n n_jobs=-1\r\n)\r\n\r\nalert_results = mc.functional.common_alerts_filter(\r\n mols=mol_list,\r\n n_jobs=-1\r\n)\r\n```\r\n\r\n### 4. Chemical Groups Detection\r\n\r\nIdentify specific chemical groups and functional groups using `medchem.groups`.\r\n\r\n**Available Groups:**\r\n- Hinge binders\r\n- Phosphate binders\r\n- Michael acceptors\r\n- Reactive groups\r\n- Custom SMARTS patterns\r\n\r\n**Usage:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\ngroup = mc.groups.ChemicalGroup(groups=[\"hinge_binders\"])\r\n\r\nhas_matches = group.has_match(mol_list)\r\n\r\nmatches = group.get_matches(mol)\r\n```\r\n\r\n### 5. Named Catalogs\r\n\r\nAccess curated collections of chemical structures through `medchem.catalogs`.\r\n\r\n**Available Catalogs:**\r\n- Functional groups\r\n- Protecting groups\r\n- Common reagents\r\n- Standard fragments\r\n\r\n**Usage:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\ncatalogs = mc.catalogs.NamedCatalogs\r\n\r\ncatalog = catalogs.get(\"functional_groups\")\r\nmatches = catalog.get_matches(mol)\r\n```\r\n\r\n### 6. Molecular Complexity\r\n\r\nCalculate complexity metrics that approximate synthetic accessibility using `medchem.complexity`.\r\n\r\n**Common Metrics:**\r\n- Bertz complexity\r\n- Whitlock complexity\r\n- Barone complexity\r\n\r\n**Usage:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\ncomplexity_score = mc.complexity.calculate_complexity(mol)\r\n\r\ncomplex_filter = mc.complexity.ComplexityFilter(max_complexity=500)\r\nresults = complex_filter(mols=mol_list)\r\n```\r\n\r\n### 7. Constraints Filtering\r\n\r\nApply custom property-based constraints using `medchem.constraints`.\r\n\r\n**Example Constraints:**\r\n- Molecular weight ranges\r\n- LogP bounds\r\n- TPSA limits\r\n- Rotatable bond counts\r\n\r\n**Usage:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nconstraints = mc.constraints.Constraints(\r\n mw_range=(200, 500),\r\n logp_range=(-2, 5),\r\n tpsa_max=140,\r\n rotatable_bonds_max=10\r\n)\r\n\r\nresults = constraints(mols=mol_list, n_jobs=-1)\r\n```\r\n\r\n### 8. Medchem Query Language\r\n\r\nUse a specialized query language for complex filtering criteria.\r\n\r\n**Query Examples:**\r\n```\r\n\"rule_of_five AND NOT common_alerts\"\r\n\r\n\"rule_of_cns AND complexity < 400\"\r\n\r\n\"rule_of_leadlike AND lilly_demerits == 0\"\r\n```\r\n\r\n**Usage:**\r\n\r\n```python\r\nimport medchem as mc\r\n\r\n\r\n### Pattern 1: Initial Triage of Compound Library\r\n\r\nFilter a large compound collection to identify drug-like candidates.\r\n\r\n```python\r\nimport datamol as dm\r\nimport medchem as mc\r\nimport pandas as pd\r\n\r\ndf = pd.read_csv(\"compounds.csv\")\r\nmols = [dm.to_mol(smi) for smi in df[\"smiles\"]]\r\n\r\nrule_filter = mc.rules.RuleFilters(rule_list=[\"rule_of_five\", \"rule_of_veber\"])\r\nrule_results = rule_filter(mols=mols, n_jobs=-1, progress=True)\r\n\r\nalert_filter = mc.structural.CommonAlertsFilters()\r\nalert_results = alert_filter(mols=mols, n_jobs=-1, progress=True)\r\n\r\ndf[\"passes_rules\"] = rule_results[\"pass\"]\r\ndf[\"has_alerts\"] = alert_results[\"has_alerts\"]\r\ndf[\"drug_like\"] = df[\"passes_rules\"] & ~df[\"has_alerts\"]\r\n\r\nfiltered_df = df[df[\"drug_like\"]]\r\nfiltered_df.to_csv(\"filtered_compounds.csv\", index=False)\r\n```\r\n\r\n### Pattern 2: Lead Optimization Filtering\r\n\r\nApply stricter criteria during lead optimization.\r\n\r\n```python\r\nimport medchem as mc\r\n\r\nfilters = {\r\n \"rules\": mc.rules.RuleFilters(rule_list=[\"rule_of_leadlike_strict\"]),\r\n \"alerts\": mc.structural.NIBRFilters(),\r\n \"lilly\": mc.structural.LillyDemeritsFilters(),\r\n \"complexity\": mc.complexity.ComplexityFilter(max_complexity=400)\r\n}\r\n\r\nresults = {}\r\nfor name, filt in filters.items():\r\n results[name] = filt(mols=candidate_mols, n_jobs=-1)\r\n\r\npasses_all = all(r[\"pass\"] for r in results.values())\r\n```\r\n\r\n### Pattern 3: Identify Specific Chemical Groups\r\n\r\nFind molecules containing specific functional groups or scaffolds.\r\n\r\n```python\r\nimport medchem as mc\r\n\r\ngroup_detector = mc.groups.ChemicalGroup(\r\n groups=[\"hinge_binders\", \"phosphate_binders\"]\r\n)\r\n\r\nmatches = group_detector.get_all_matches(mol_list)",
"name": "medchem",
"id": "scientific-pkg-medchem",
"sections": {
"Best Practices": "1. **Context Matters**: Don't blindly apply filters. Understand the biological target and chemical space.\r\n\r\n2. **Combine Multiple Filters**: Use rules, structural alerts, and domain knowledge together for better decisions.\r\n\r\n3. **Use Parallelization**: For large datasets (>1000 molecules), always use `n_jobs=-1` for parallel processing.\r\n\r\n4. **Iterative Refinement**: Start with broad filters (Ro5), then apply more specific criteria (CNS, leadlike) as needed.\r\n\r\n5. **Document Filtering Decisions**: Track which molecules were filtered out and why for reproducibility.\r\n\r\n6. **Validate Results**: Remember that marketed drugs often fail standard filters—use these as guidelines, not absolute rules.\r\n\r\n7. **Consider Prodrugs**: Molecules designed as prodrugs may intentionally violate standard medicinal chemistry rules.",
"Installation": "pip install medchem\r\n```",
"Overview": "Medchem is a Python library for molecular filtering and prioritization in drug discovery workflows. Apply hundreds of well-established and novel molecular filters, structural alerts, and medicinal chemistry rules to efficiently triage and prioritize compound libraries at scale. Rules and filters are context-specific—use as guidelines combined with domain expertise.",
"When to Use This Skill": "This skill should be used when:\r\n- Applying drug-likeness rules (Lipinski, Veber, etc.) to compound libraries\r\n- Filtering molecules by structural alerts or PAINS patterns\r\n- Prioritizing compounds for lead optimization\r\n- Assessing compound quality and medicinal chemistry properties\r\n- Detecting reactive or problematic functional groups\r\n- Calculating molecular complexity metrics",
"Resources": "### references/api_guide.md\r\nComprehensive API reference covering all medchem modules with detailed function signatures, parameters, and return types.\r\n\r\n### references/rules_catalog.md\r\nComplete catalog of available rules, filters, and alerts with descriptions, thresholds, and literature references.\r\n\r\n### scripts/filter_molecules.py\r\nProduction-ready script for batch filtering workflows. Supports multiple input formats (CSV, SDF, SMILES), configurable filter combinations, and detailed reporting.\r\n\r\n**Usage:**\r\n```bash\r\npython scripts/filter_molecules.py input.csv --rules rule_of_five,rule_of_cns --alerts nibr --output filtered.csv\r\n```",
"Core Capabilities": "query = mc.query.parse(\"rule_of_five AND NOT common_alerts\")\r\nresults = query.apply(mols=mol_list, n_jobs=-1)\r\n```",
"Documentation": "Official documentation: https://medchem-docs.datamol.io/\r\nGitHub repository: https://github.com/datamol-io/medchem",
"Workflow Patterns": "mol_with_groups = [mol for mol, match in zip(mol_list, matches) if match]\r\n```"
}
}---
name: medchem
description: "Medicinal chemistry filters. Apply drug-likeness rules (Lipinski, Veber), PAINS filters, structural alerts, complexity metrics, for compound prioritization and library filtering."
---
# Medchem
## Overview
Medchem is a Python library for molecular filtering and prioritization in drug discovery workflows. Apply hundreds of well-established and novel molecular filters, structural alerts, and medicinal chemistry rules to efficiently triage and prioritize compound libraries at scale. Rules and filters are context-specific—use as guidelines combined with domain expertise.
## When to Use This Skill
This skill should be used when:
- Applying drug-likeness rules (Lipinski, Veber, etc.) to compound libraries
- Filtering molecules by structural alerts or PAINS patterns
- Prioritizing compounds for lead optimization
- Assessing compound quality and medicinal chemistry properties
- Detecting reactive or problematic functional groups
- Calculating molecular complexity metrics
## Installation
Install medchem via conda or pip:
```bash
# Via conda
micromamba install -c conda-forge medchem
# Via pip
pip install medchem
```
## Core Capabilities
### 1. Medicinal Chemistry Rules
Apply established drug-likeness rules to molecules using the `medchem.rules` module.
**Available Rules:**
- Rule of Five (Lipinski)
- Rule of Oprea
- Rule of CNS
- Rule of leadlike (soft and strict)
- Rule of three
- Rule of Reos
- Rule of drug
- Rule of Veber
- Golden triangle
- PAINS filters
**Single Rule Application:**
```python
import medchem as mc
# Apply Rule of Five to a SMILES string
smiles = "CC(=O)OC1=CC=CC=C1C(=O)O" # Aspirin
passes = mc.rules.basic_rules.rule_of_five(smiles)
# Returns: True
# Check specific rules
passes_oprea = mc.rules.basic_rules.rule_of_oprea(smiles)
passes_cns = mc.rules.basic_rules.rule_of_cns(smiles)
```
**Multiple Rules with RuleFilters:**
```python
import datamol as dm
import medchem as mc
# Load molecules
mols = [dm.to_mol(smiles) for smiles in smiles_list]
# Create filter with multiple rules
rfilter = mc.rules.RuleFilters(
rule_list=[
"rule_of_five",
"rule_of_oprea",
"rule_of_cns",
"rule_of_leadlike_soft"
]
)
# Apply filters with parallelization
results = rfilter(
mols=mols,
n_jobs=-1, # Use all CPU cores
progress=True
)
```
**Result Format:**
Results are returned as dictionaries with pass/fail status and detailed information for each rule.
### 2. Structural Alert Filters
Detect potentially problematic structural patterns using the `medchem.structural` module.
**Available Filters:**
1. **Common Alerts** - General structural alerts derived from ChEMBL curation and literature
2. **NIBR Filters** - Novartis Institutes for BioMedical Research filter set
3. **Lilly Demerits** - Eli Lilly's demerit-based system (275 rules, molecules rejected at >100 demerits)
**Common Alerts:**
```python
import medchem as mc
# Create filter
alert_filter = mc.structural.CommonAlertsFilters()
# Check single molecule
mol = dm.to_mol("c1ccccc1")
has_alerts, details = alert_filter.check_mol(mol)
# Batch filtering with parallelization
results = alert_filter(
mols=mol_list,
n_jobs=-1,
progress=True
)
```
**NIBR Filters:**
```python
import medchem as mc
# Apply NIBR filters
nibr_filter = mc.structural.NIBRFilters()
results = nibr_filter(mols=mol_list, n_jobs=-1)
```
**Lilly Demerits:**
```python
import medchem as mc
# Calculate Lilly demerits
lilly = mc.structural.LillyDemeritsFilters()
results = lilly(mols=mol_list, n_jobs=-1)
# Each result includes demerit score and whether it passes (≤100 demerits)
```
### 3. Functional API for High-Level Operations
The `medchem.functional` module provides convenient functions for common workflows.
**Quick Filtering:**
```python
import medchem as mc
# Apply NIBR filters to a list
filter_ok = mc.functional.nibr_filter(
mols=mol_list,
n_jobs=-1
)
# Apply common alerts
alert_results = mc.functional.common_alerts_filter(
mols=mol_list,
n_jobs=-1
)
```
### 4. Chemical Groups Detection
Identify specific chemical groups and functional groups using `medchem.groups`.
**Available Groups:**
- Hinge binders
- Phosphate binders
- Michael acceptors
- Reactive groups
- Custom SMARTS patterns
**Usage:**
```python
import medchem as mc
# Create group detector
group = mc.groups.ChemicalGroup(groups=["hinge_binders"])
# Check for matches
has_matches = group.has_match(mol_list)
# Get detailed match information
matches = group.get_matches(mol)
```
### 5. Named Catalogs
Access curated collections of chemical structures through `medchem.catalogs`.
**Available Catalogs:**
- Functional groups
- Protecting groups
- Common reagents
- Standard fragments
**Usage:**
```python
import medchem as mc
# Access named catalogs
catalogs = mc.catalogs.NamedCatalogs
# Use catalog for matching
catalog = catalogs.get("functional_groups")
matches = catalog.get_matches(mol)
```
### 6. Molecular Complexity
Calculate complexity metrics that approximate synthetic accessibility using `medchem.complexity`.
**Common Metrics:**
- Bertz complexity
- Whitlock complexity
- Barone complexity
**Usage:**
```python
import medchem as mc
# Calculate complexity
complexity_score = mc.complexity.calculate_complexity(mol)
# Filter by complexity threshold
complex_filter = mc.complexity.ComplexityFilter(max_complexity=500)
results = complex_filter(mols=mol_list)
```
### 7. Constraints Filtering
Apply custom property-based constraints using `medchem.constraints`.
**Example Constraints:**
- Molecular weight ranges
- LogP bounds
- TPSA limits
- Rotatable bond counts
**Usage:**
```python
import medchem as mc
# Define constraints
constraints = mc.constraints.Constraints(
mw_range=(200, 500),
logp_range=(-2, 5),
tpsa_max=140,
rotatable_bonds_max=10
)
# Apply constraints
results = constraints(mols=mol_list, n_jobs=-1)
```
### 8. Medchem Query Language
Use a specialized query language for complex filtering criteria.
**Query Examples:**
```
# Molecules passing Ro5 AND not having common alerts
"rule_of_five AND NOT common_alerts"
# CNS-like molecules with low complexity
"rule_of_cns AND complexity < 400"
# Leadlike molecules without Lilly demerits
"rule_of_leadlike AND lilly_demerits == 0"
```
**Usage:**
```python
import medchem as mc
# Parse and apply query
query = mc.query.parse("rule_of_five AND NOT common_alerts")
results = query.apply(mols=mol_list, n_jobs=-1)
```
## Workflow Patterns
### Pattern 1: Initial Triage of Compound Library
Filter a large compound collection to identify drug-like candidates.
```python
import datamol as dm
import medchem as mc
import pandas as pd
# Load compound library
df = pd.read_csv("compounds.csv")
mols = [dm.to_mol(smi) for smi in df["smiles"]]
# Apply primary filters
rule_filter = mc.rules.RuleFilters(rule_list=["rule_of_five", "rule_of_veber"])
rule_results = rule_filter(mols=mols, n_jobs=-1, progress=True)
# Apply structural alerts
alert_filter = mc.structural.CommonAlertsFilters()
alert_results = alert_filter(mols=mols, n_jobs=-1, progress=True)
# Combine results
df["passes_rules"] = rule_results["pass"]
df["has_alerts"] = alert_results["has_alerts"]
df["drug_like"] = df["passes_rules"] & ~df["has_alerts"]
# Save filtered compounds
filtered_df = df[df["drug_like"]]
filtered_df.to_csv("filtered_compounds.csv", index=False)
```
### Pattern 2: Lead Optimization Filtering
Apply stricter criteria during lead optimization.
```python
import medchem as mc
# Create comprehensive filter
filters = {
"rules": mc.rules.RuleFilters(rule_list=["rule_of_leadlike_strict"]),
"alerts": mc.structural.NIBRFilters(),
"lilly": mc.structural.LillyDemeritsFilters(),
"complexity": mc.complexity.ComplexityFilter(max_complexity=400)
}
# Apply all filters
results = {}
for name, filt in filters.items():
results[name] = filt(mols=candidate_mols, n_jobs=-1)
# Identify compounds passing all filters
passes_all = all(r["pass"] for r in results.values())
```
### Pattern 3: Identify Specific Chemical Groups
Find molecules containing specific functional groups or scaffolds.
```python
import medchem as mc
# Create group detector for multiple groups
group_detector = mc.groups.ChemicalGroup(
groups=["hinge_binders", "phosphate_binders"]
)
# Screen library
matches = group_detector.get_all_matches(mol_list)
# Filter molecules with desired groups
mol_with_groups = [mol for mol, match in zip(mol_list, matches) if match]
```
## Best Practices
1. **Context Matters**: Don't blindly apply filters. Understand the biological target and chemical space.
2. **Combine Multiple Filters**: Use rules, structural alerts, and domain knowledge together for better decisions.
3. **Use Parallelization**: For large datasets (>1000 molecules), always use `n_jobs=-1` for parallel processing.
4. **Iterative Refinement**: Start with broad filters (Ro5), then apply more specific criteria (CNS, leadlike) as needed.
5. **Document Filtering Decisions**: Track which molecules were filtered out and why for reproducibility.
6. **Validate Results**: Remember that marketed drugs often fail standard filters—use these as guidelines, not absolute rules.
7. **Consider Prodrugs**: Molecules designed as prodrugs may intentionally violate standard medicinal chemistry rules.
## Resources
### references/api_guide.md
Comprehensive API reference covering all medchem modules with detailed function signatures, parameters, and return types.
### references/rules_catalog.md
Complete catalog of available rules, filters, and alerts with descriptions, thresholds, and literature references.
### scripts/filter_molecules.py
Production-ready script for batch filtering workflows. Supports multiple input formats (CSV, SDF, SMILES), configurable filter combinations, and detailed reporting.
**Usage:**
```bash
python scripts/filter_molecules.py input.csv --rules rule_of_five,rule_of_cns --alerts nibr --output filtered.csv
```
## Documentation
Official documentation: https://medchem-docs.datamol.io/
GitHub repository: https://github.com/datamol-io/medchem