部分SMILES调用Chem.RDKFingerprint报C++签名不匹配问题排查
配体匹配中的RDKit计算异常问题分析
问题背景
尝试匹配UniProt与PDB条目中的同一配体:多数配体(如FAD)三字母编码一致,但部分存在差异,例如血红蛋白1a9w链A在PDB中为“HEM”,对应UniProt条目(P69905)为“heme b”,其ChEBI ID为CHEBI:60344。
从ChEBI官网下载完整SDF文件后,找到3个相关血红素配体。以CHEBI:60344为参考计算Tanimoto系数时,部分配体运行正常,但CHEBI:26355触发Python无法捕获的C++异常;调整ChEBI ID顺序后代码直接报错无法得到系数。
环境:conda安装的rdkit、bioservices与Python3.9,运行于旧版Mac Pro(High Sierra系统,无法升级)。
执行代码
from rdkit import Chem, DataStructs from bioservices import ChEBI heme = ChEBI() heme_chebi_id = "CHEBI:60344" heme_smiles = heme.getCompleteEntity(heme_chebi_id).smiles target = Chem.MolFromSmiles(heme_smiles) fp2 = Chem.RDKFingerprint(target) for chebi_id in ["CHEBI:17627", "CHEBI:26355"]: ch = ChEBI() smiley = ch.getCompleteEntity(chebi_id).smiles print("reference:", heme_chebi_id) print("target: ", chebi_id) print("reference:", heme_smiles) print("target: ", smiley) ref = Chem.MolFromSmiles(smiley) fp1 = Chem.RDKFingerprint(ref) Tan = DataStructs.TanimotoSimilarity(fp1, fp2) print(Tan) print("-" * 64) exit()
输出结果
reference: CHEBI:60344 target: CHEBI:17627 reference: CC1=C(CCC([O-])=O)C2=[N+]3C1=Cc1c(C)c(C=C)c4C=C5C(C)=C(C=C)C6=[N+]5[Fe--]3(n14)n1c(=C6)c(C)c(CCC([O-])=O)c1=C2 target: CC1=C(CCC(O)=O)C2=[N+]3C1=Cc1c(C)c(C=C)c4C=C5C(C)=C(C=C)C6=[N+]5[Fe--]3(n14)n1c(=C6)c(C)c(CCC(O)=O)c1=C2 Tanimoto coefficient: 1.0 reference: CHEBI:60344 target: CHEBI:26355 reference: CC1=C(CCC([O-])=O)C2=[N+]3C1=Cc1c(C)c(C=C)c4C=C5C(C)=C(C=C)C6=[N+]5[Fe--]3(n14)n1c(=C6)c(C)c(CCC([O-])=O)c1=C2 target: CC1=C(CCC(O)=O)C2=[N]3C1=Cc1c(C)c(C=C)c4C=C5C(C)=C(C=C)C6=[N]5[Fe]3(n14)n1c(=C6)c(C)c(CCC(O)=O)c1=C2 [12:36:26] Explicit valence for atom # 9 N, 4, is greater than permitted Traceback (most recent call last): File "/Volumes/Users/harry/icl/phyre2-ligand/./tanimoto_test.py", line 20, in <module> fp1 = Chem.RDKFingerprint(ref) Boost.Python.ArgumentError: Python argument types in rdkit.Chem.rdmolops.RDKFingerprint(NoneType) did not match C++ signature: RDKFingerprint(RDKit::ROMol mol, unsigned int minPath=1, unsigned int maxPath=7, unsigned int fpSize=2048, unsigned int nBitsPerHash=2, bool useHs=True, double tgtDensity=0.0, unsigned int minSize=128, bool branchedPaths=True, bool useBondOrder=True, boost::python::api::object atomInvariants=0, boost::python::api::object fromAtoms=0, boost::python::api::object atomBits=None, boost::python::api::object bitInfo=None)
问题原因分析
- ChEBI的SMILES字符串错误:CHEBI:26355返回的SMILES中,N原子的价态标注不符合化学规则(错误提示显示#9号N原子显式价为4,超出允许范围),导致RDKit无法将其解析为有效的分子对象(
ref为None)。 - RDKit代码实现错误:代码中未检查
Chem.MolFromSmiles()的返回值,当解析失败返回None时,直接将其传入RDKFingerprint(),触发C++层的参数类型不匹配异常。 - RDKit本身/bioservices模块无问题:RDKit的错误提示是解析无效SMILES的正常反馈;bioservices正确获取了ChEBI数据库返回的SMILES内容,不存在模块功能异常。
修复方案
1. 增加错误处理逻辑
在解析SMILES后检查分子对象是否有效,避免传入None到指纹计算函数:
from rdkit import Chem, DataStructs from bioservices import ChEBI # 只初始化一次ChEBI实例,避免重复创建 hebi_client = ChEBI() heme_chebi_id = "CHEBI:60344" heme_smiles = hebi_client.getCompleteEntity(heme_chebi_id).smiles target = Chem.MolFromSmiles(heme_smiles) if not target: print(f"Failed to parse reference SMILES for {heme_chebi_id}") exit() fp2 = Chem.RDKFingerprint(target) for chebi_id in ["CHEBI:17627", "CHEBI:26355"]: smiley = hebi_client.getCompleteEntity(chebi_id).smiles print("reference:", heme_chebi_id) print("target: ", chebi_id) print("reference:", heme_smiles) print("target: ", smiley) ref = Chem.MolFromSmiles(smiley) if not ref: print(f"Failed to parse SMILES for {chebi_id}, skipping...") print("-" * 64) continue fp1 = Chem.RDKFingerprint(ref) tanimoto = DataStructs.TanimotoSimilarity(fp1, fp2) print(f"Tanimoto coefficient: {tanimoto}") print("-" * 64)
2. 使用ChEBI的SDF文件获取结构
由于SMILES可能存在价态或立体信息丢失,建议直接从下载的SDF文件中读取分子结构,而非通过API获取SMILES:
from rdkit import Chem, DataStructs # 读取ChEBI SDF文件 suppl = Chem.SDMolSupplier("chebi_lite_3star.sdf") # 构建ChEBI ID到分子的映射 chebi_mol_map = {} for mol in suppl: if mol is None: continue chebi_id = mol.GetProp("ChEBI ID") chebi_mol_map[chebi_id] = mol # 获取参考分子 ref_mol = chebi_mol_map.get("CHEBI:60344") if not ref_mol: print("Reference molecule not found in SDF") exit() ref_fp = Chem.RDKFingerprint(ref_mol) # 计算目标配体的Tanimoto系数 for chebi_id in ["CHEBI:17627", "CHEBI:26355"]: target_mol = chebi_mol_map.get(chebi_id) if not target_mol: print(f"Molecule {chebi_id} not found in SDF") continue target_fp = Chem.RDKFingerprint(target_mol) tanimoto = DataStructs.TanimotoSimilarity(ref_fp, target_fp) print(f"{heme_chebi_id} vs {chebi_id}: Tanimoto = {tanimoto}")
内容的提问来源于stack exchange,提问作者Ubuntu-on-Mac
相关产品推荐
相关产品推荐

