Samad14 commited on
Commit
0ed4824
Β·
1 Parent(s): 8be46a8

fix: remove pybel bindings (causes segfault on Render), use obabel CLI subprocess only

Browse files
bioai-platform/backend/app/tools/docking.py CHANGED
@@ -31,48 +31,11 @@ def _find_obabel() -> str | None:
31
  VINA_CMD = shutil.which("vina") or "/usr/local/bin/vina"
32
  OBABEL_CMD = _find_obabel()
33
 
34
- # ── in-process OpenBabel bindings (no subprocess – saves ~200 MB RAM) ───
35
-
36
- def _pdb_to_pdbqt_pybel(pdb_path: str, out_path: str) -> bool:
37
- try:
38
- from openbabel import pybel
39
- mol = next(pybel.readfile("pdb", pdb_path))
40
- mol.write("pdbqt", out_path, overwrite=True)
41
- if not os.path.exists(out_path):
42
- return False
43
- # PDBQT writer treats the molecule as flexible by default, adding
44
- # ROOT/BRANCH/ENDROOT/ENDBRANCH. For a rigid receptor these tags
45
- # cause "Unknown or inappropriate tag found in rigid receptor" from
46
- # vina. Strip them β€” the ATOM records are already correct.
47
- with open(out_path) as _f:
48
- _lines = _f.readlines()
49
- _keep = [l for l in _lines
50
- if not l.startswith(("ROOT", "ENDROOT", "BRANCH", "ENDBRANCH",
51
- "TORSDOF", "TORSDEG", "TORSLIB"))]
52
- if len(_keep) != len(_lines):
53
- with open(out_path, "w") as _f:
54
- _f.writelines(_keep)
55
- return True
56
- except Exception:
57
- return False
58
-
59
-
60
- def _smiles_to_pdbqt_pybel(smiles: str, out_path: str) -> bool:
61
- try:
62
- from openbabel import pybel
63
- mol = pybel.readstring("smi", smiles)
64
- mol.addh()
65
- mol.make3D()
66
- mol.write("pdbqt", out_path, overwrite=True)
67
- return os.path.exists(out_path)
68
- except Exception:
69
- return False
70
-
71
  # ── self-healing binary download ─────────────────────────────────────────
72
  _VINA_URL = "https://github.com/ccsb-scripps/AutoDock-Vina/releases/download/v1.2.7/vina_1.2.7_linux_x86_64"
73
 
74
  def _pip_install_obabel() -> str | None:
75
- """Install openbabel-wheel via pip and return the obabel path."""
76
  import subprocess as _sp
77
  logger.info("obabel not found β€” installing openbabel-wheel via pip")
78
  try:
@@ -589,39 +552,37 @@ class DockingTool(BaseTool):
589
  with open(clean_path, "w") as f:
590
  f.write(cleaned)
591
 
592
- # 3. Convert protein to PDBQT (in-process pybel β†’ no subprocess, saves ~200+ MB)
593
  protein_pdbqt = os.path.join(tmpdir, "protein.pdbqt")
594
- if not _pdb_to_pdbqt_pybel(clean_path, protein_pdbqt):
595
- if not OBABEL_CMD:
596
- OBABEL_CMD = _pip_install_obabel()
597
- if not OBABEL_CMD:
598
- return {"error": "Open Babel not available – cannot prepare protein PDBQT."}
599
- proc = await asyncio.create_subprocess_exec(
600
- OBABEL_CMD, clean_path, "-O", protein_pdbqt, "-xr",
601
- stdout=asyncio.subprocess.PIPE,
602
- stderr=asyncio.subprocess.PIPE,
603
- )
604
- _, stderr = await proc.communicate()
605
- if proc.returncode != 0 or not os.path.exists(protein_pdbqt):
606
- err = stderr.decode() if stderr else "obabel failed"
607
- return {"error": f"Protein PDBQT preparation failed: {err}"}
608
 
609
- # 4. Convert SMILES to 3D PDBQT (in-process pybel β†’ no subprocess)
610
  ligand_pdbqt = os.path.join(tmpdir, "ligand.pdbqt")
611
- if not _smiles_to_pdbqt_pybel(smiles, ligand_pdbqt):
612
- if not OBABEL_CMD:
613
- OBABEL_CMD = _pip_install_obabel()
614
- if not OBABEL_CMD:
615
- return {"error": "Open Babel not available – cannot prepare ligand PDBQT."}
616
- proc = await asyncio.create_subprocess_exec(
617
- OBABEL_CMD, f"-:{smiles}", "-O", ligand_pdbqt, "--gen3d", "-h",
618
- stdout=asyncio.subprocess.PIPE,
619
- stderr=asyncio.subprocess.PIPE,
620
- )
621
- _, stderr = await proc.communicate()
622
- if proc.returncode != 0 or not os.path.exists(ligand_pdbqt):
623
- err = stderr.decode() if stderr else "obabel failed"
624
- return {"error": f"Ligand PDBQT preparation failed: {err}"}
625
 
626
  # 5. Determine binding site box
627
  center = _find_ligand_center(pdb_content)
 
31
  VINA_CMD = shutil.which("vina") or "/usr/local/bin/vina"
32
  OBABEL_CMD = _find_obabel()
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  # ── self-healing binary download ─────────────────────────────────────────
35
  _VINA_URL = "https://github.com/ccsb-scripps/AutoDock-Vina/releases/download/v1.2.7/vina_1.2.7_linux_x86_64"
36
 
37
  def _pip_install_obabel() -> str | None:
38
+ """Install openbabel CLI via pip and return the obabel path."""
39
  import subprocess as _sp
40
  logger.info("obabel not found β€” installing openbabel-wheel via pip")
41
  try:
 
552
  with open(clean_path, "w") as f:
553
  f.write(cleaned)
554
 
555
+ # 3. Convert protein to PDBQT (via obabel CLI subprocess)
556
  protein_pdbqt = os.path.join(tmpdir, "protein.pdbqt")
557
+ if not OBABEL_CMD:
558
+ OBABEL_CMD = _pip_install_obabel()
559
+ if not OBABEL_CMD:
560
+ return {"error": "Open Babel not available – cannot prepare protein PDBQT."}
561
+ proc = await asyncio.create_subprocess_exec(
562
+ OBABEL_CMD, clean_path, "-O", protein_pdbqt, "-xr",
563
+ stdout=asyncio.subprocess.PIPE,
564
+ stderr=asyncio.subprocess.PIPE,
565
+ )
566
+ _, stderr = await proc.communicate()
567
+ if proc.returncode != 0 or not os.path.exists(protein_pdbqt):
568
+ err = stderr.decode() if stderr else "obabel failed"
569
+ return {"error": f"Protein PDBQT preparation failed: {err}"}
 
570
 
571
+ # 4. Convert SMILES to 3D PDBQT (via obabel CLI subprocess)
572
  ligand_pdbqt = os.path.join(tmpdir, "ligand.pdbqt")
573
+ if not OBABEL_CMD:
574
+ OBABEL_CMD = _pip_install_obabel()
575
+ if not OBABEL_CMD:
576
+ return {"error": "Open Babel not available – cannot prepare ligand PDBQT."}
577
+ proc = await asyncio.create_subprocess_exec(
578
+ OBABEL_CMD, f"-:{smiles}", "-O", ligand_pdbqt, "--gen3d", "-h",
579
+ stdout=asyncio.subprocess.PIPE,
580
+ stderr=asyncio.subprocess.PIPE,
581
+ )
582
+ _, stderr = await proc.communicate()
583
+ if proc.returncode != 0 or not os.path.exists(ligand_pdbqt):
584
+ err = stderr.decode() if stderr else "obabel failed"
585
+ return {"error": f"Ligand PDBQT preparation failed: {err}"}
 
586
 
587
  # 5. Determine binding site box
588
  center = _find_ligand_center(pdb_content)