rowan-python 3.0.5__py3-none-any.whl → 3.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rowan/molecule.py CHANGED
@@ -52,28 +52,36 @@ class Molecule(BaseModel):
52
52
  return cls(_stjames=stjames.Molecule.from_smiles(smiles))
53
53
 
54
54
  @classmethod
55
- def from_xyz(cls, xyz_string: str, charge: int = 0, multiplicity: int = 1) -> Self:
55
+ def from_xyz(
56
+ cls, xyz_string: str, charge: int | None = None, multiplicity: int | None = None
57
+ ) -> Self:
56
58
  """
57
- Create molecule from XYZ string.
59
+ Create Molecule from XYZ string.
58
60
 
59
- :param xyz_string: XYZ format string.
60
- :param charge: Molecular charge (default 0).
61
- :param multiplicity: Spin multiplicity (default 1).
62
- :returns: Molecule instance.
61
+ :param xyz_string: XYZ format string
62
+ :param charge: charge
63
+ :param multiplicity: spin multiplicity
64
+ :returns: Molecule
63
65
  """
64
- stj = stjames.Molecule.from_xyz(xyz_string)
65
- stj = stjames.Molecule(atoms=stj.atoms, charge=charge, multiplicity=multiplicity)
66
- return cls(_stjames=stj)
66
+ return cls(
67
+ _stjames=stjames.Molecule.from_xyz(
68
+ xyz_string,
69
+ charge=charge,
70
+ multiplicity=multiplicity,
71
+ )
72
+ )
67
73
 
68
74
  @classmethod
69
- def from_xyz_file(cls, path: str | Path, charge: int = 0, multiplicity: int = 1) -> Self:
75
+ def from_xyz_file(
76
+ cls, path: str | Path, charge: int | None = None, multiplicity: int | None = None
77
+ ) -> Self:
70
78
  """
71
79
  Create molecule from XYZ file.
72
80
 
73
- :param path: Path to XYZ file.
74
- :param charge: Molecular charge (default 0).
75
- :param multiplicity: Spin multiplicity (default 1).
76
- :returns: Molecule instance.
81
+ :param path: path to XYZ file
82
+ :param charge: charge
83
+ :param multiplicity: spin multiplicity
84
+ :returns: Molecule
77
85
  """
78
86
  return cls.from_xyz(Path(path).read_text(), charge=charge, multiplicity=multiplicity)
79
87
 
@@ -82,8 +90,8 @@ class Molecule(BaseModel):
82
90
  """
83
91
  Create from stjames.Molecule.
84
92
 
85
- :param stj: stjames.Molecule instance.
86
- :returns: Molecule instance.
93
+ :param stj: stjames.Molecule
94
+ :returns: Molecule
87
95
  """
88
96
  return cls(_stjames=stj)
89
97
 
rowan/protein.py CHANGED
@@ -305,7 +305,7 @@ def list_proteins(
305
305
 
306
306
 
307
307
  def upload_protein(
308
- name: str, file_path: Path, project_uuid: str | Project | None = None
308
+ name: str, file_path: str | Path, project_uuid: str | Project | None = None
309
309
  ) -> Protein:
310
310
  """
311
311
  Uploads a protein from a PDB file to the API.
@@ -315,6 +315,7 @@ def upload_protein(
315
315
  :returns: Protein object representing the uploaded protein
316
316
  :raises requests.HTTPError: if the request to the API fails
317
317
  """
318
+ file_path = Path(file_path)
318
319
  if isinstance(project_uuid, Project):
319
320
  project_uuid = project_uuid.uuid
320
321
  with api_client() as client:
@@ -84,6 +84,7 @@ from .multistage_optimization import (
84
84
  )
85
85
  from .nmr import NMRPeak, NMRResult, submit_nmr_workflow
86
86
  from .pka import pKaMicrostate, pKaResult, submit_pka_workflow
87
+ from .pocket_detection import Pocket, PocketDetectionResult, submit_pocket_detection_workflow
87
88
  from .pose_analysis_md import PoseAnalysisMDResult, submit_pose_analysis_md_workflow
88
89
  from .protein_binder_design import (
89
90
  ProteinBinder,
@@ -3,6 +3,7 @@
3
3
  from dataclasses import dataclass
4
4
 
5
5
  import stjames
6
+ from stjames import ENGINE_METHODS, Engine, Method
6
7
 
7
8
  from ..folder import Folder
8
9
  from ..types import MoleculeInput
@@ -155,6 +156,7 @@ def submit_electronic_properties_workflow(
155
156
  :param webhook_url: URL that Rowan will POST to when the workflow completes.
156
157
  :param is_draft: If True, submit the workflow as a draft without starting execution.
157
158
  :returns: Workflow object representing the submitted workflow.
159
+ :raises ValueError: If the method is not supported by the psi4 engine.
158
160
  :raises requests.HTTPError: if the request to the API fails.
159
161
  """
160
162
  if folder and folder_uuid:
@@ -164,7 +166,15 @@ def submit_electronic_properties_workflow(
164
166
  initial_molecule = molecule_to_dict(initial_molecule)
165
167
 
166
168
  if isinstance(method, str):
167
- method = stjames.Method(method)
169
+ method = Method(method)
170
+
171
+ supported_methods = ENGINE_METHODS[Engine.PSI4]
172
+ if method not in supported_methods:
173
+ supported_names = sorted(m.value for m in supported_methods)
174
+ raise ValueError(
175
+ f"Method '{method.value}' is not supported by the psi4 engine. "
176
+ f"Supported methods: {', '.join(supported_names)}"
177
+ )
168
178
 
169
179
  settings = stjames.Settings(method=method, basis_set=basis_set)
170
180
 
rowan/workflows/pka.py CHANGED
@@ -183,13 +183,21 @@ def submit_pka_workflow(
183
183
  )
184
184
  if method in _PKA_SMILES_METHODS and not initial_smiles:
185
185
  raise ValueError(
186
- f"{method} requires a SMILES string. "
187
- "Provide a SMILES string, not a 3D structure."
186
+ f"{method} requires a SMILES string. Provide a SMILES string, not a 3D structure."
188
187
  )
189
188
  if method in _PKA_WATER_ONLY_METHODS and solvent != "water":
190
189
  raise ValueError(f"{method} only supports water as solvent.")
191
190
 
192
- protonate_elements = protonate_elements or [7]
191
+ if method == "chemprop_nevolianis2025" and protonate_elements:
192
+ raise ValueError(
193
+ "chemprop_nevolianis2025 was only trained on deprotonation data; "
194
+ "protonation is disabled. Leave `protonate_elements` unset or pass []."
195
+ )
196
+
197
+ if method == "chemprop_nevolianis2025":
198
+ protonate_elements = []
199
+ else:
200
+ protonate_elements = protonate_elements or [7]
193
201
  deprotonate_elements = deprotonate_elements or [7, 8, 16]
194
202
 
195
203
  workflow = stjames.pKaWorkflow(
@@ -0,0 +1,112 @@
1
+ """Pocket detection workflow - detect potential binding sites on a protein."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ import stjames
6
+
7
+ from ..folder import Folder
8
+ from ..protein import Protein
9
+ from ..utils import api_client
10
+ from .base import Workflow, WorkflowResult, register_result
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class Pocket:
15
+ """
16
+ A detected binding pocket.
17
+
18
+ :param sphere_centers: centers of detected spheres, in Å
19
+ :param sphere_radii: radii of detected spheres, in Å
20
+ :param volume: pocket volume, in ų
21
+ :param score: druggability/quality score; larger is better
22
+ :param pocket_center: center of axis-aligned bounding box, in Å
23
+ :param pocket_sides: side lengths of axis-aligned bounding box, in Å
24
+ :param residue_numbers: residue numbers lining the pocket
25
+ """
26
+
27
+ sphere_centers: tuple[tuple[float, float, float], ...]
28
+ sphere_radii: tuple[float, ...]
29
+ volume: float
30
+ score: float
31
+ pocket_center: tuple[float, float, float]
32
+ pocket_sides: tuple[float, float, float]
33
+ residue_numbers: tuple[int, ...]
34
+
35
+
36
+ @register_result("pocket_detection")
37
+ class PocketDetectionResult(WorkflowResult):
38
+ """Result from a pocket-detection workflow."""
39
+
40
+ _stjames_class = stjames.PocketDetectionWorkflow
41
+
42
+ def __repr__(self) -> str:
43
+ return f"<PocketDetectionResult pockets={len(self.pockets)}>"
44
+
45
+ @property
46
+ def pockets(self) -> list[Pocket]:
47
+ """Detected pockets, in the order returned by the backend."""
48
+ raw = getattr(self._workflow, "pockets", []) or []
49
+ return [
50
+ Pocket(
51
+ sphere_centers=tuple(tuple(c) for c in p.sphere_centers),
52
+ sphere_radii=tuple(p.sphere_radii),
53
+ volume=p.volume,
54
+ score=p.score,
55
+ pocket_center=tuple(p.pocket_center),
56
+ pocket_sides=tuple(p.pocket_sides),
57
+ residue_numbers=tuple(p.residue_numbers),
58
+ )
59
+ for p in raw
60
+ ]
61
+
62
+
63
+ def submit_pocket_detection_workflow(
64
+ protein: str | Protein,
65
+ merge_distance: float = 1.75,
66
+ name: str = "Pocket Detection Workflow",
67
+ folder_uuid: str | None = None,
68
+ folder: Folder | None = None,
69
+ max_credits: int | None = None,
70
+ webhook_url: str | None = None,
71
+ is_draft: bool = False,
72
+ ) -> Workflow:
73
+ """
74
+ Submits a pocket-detection workflow to the API.
75
+
76
+ :param protein: protein to analyze. Can be a UUID or a Protein object.
77
+ :param merge_distance: distance for merging pocket spheres, in Å
78
+ :param name: name of the workflow
79
+ :param folder_uuid: UUID of the folder to place the workflow in
80
+ :param folder: Folder object to store the workflow in
81
+ :param max_credits: maximum number of credits to use for the workflow
82
+ :param webhook_url: URL that Rowan will POST to when the workflow completes
83
+ :param is_draft: if True, submit the workflow as a draft without starting execution
84
+ :returns: Workflow object representing the submitted workflow
85
+ :raises requests.HTTPError: if the request to the API fails
86
+ """
87
+ if folder and folder_uuid:
88
+ raise ValueError("Provide either `folder` or `folder_uuid`, not both.")
89
+ if folder:
90
+ folder_uuid = folder.uuid
91
+ if isinstance(protein, Protein):
92
+ protein = protein.uuid
93
+
94
+ workflow = stjames.PocketDetectionWorkflow(
95
+ protein=protein,
96
+ merge_distance=merge_distance,
97
+ )
98
+
99
+ data = {
100
+ "workflow_type": "pocket_detection",
101
+ "workflow_data": workflow.model_dump(mode="json"),
102
+ "name": name,
103
+ "folder_uuid": folder_uuid,
104
+ "max_credits": max_credits,
105
+ "webhook_url": webhook_url,
106
+ "is_draft": is_draft,
107
+ }
108
+
109
+ with api_client() as client:
110
+ response = client.post("/workflow", json=data)
111
+ response.raise_for_status()
112
+ return Workflow(**response.json())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rowan-python
3
- Version: 3.0.5
3
+ Version: 3.0.7
4
4
  Summary: Rowan Python Library
5
5
  Project-URL: Homepage, https://github.com/rowansci/rowan-client
6
6
  Project-URL: Bug Tracker, https://github.com/rowansci/rowan-client/issues
@@ -3,16 +3,16 @@ rowan/calculation.py,sha256=lZZ52DxPsuJWCTzFZXjhauHK6dV0KCUwzoxtmoxSY48,3442
3
3
  rowan/config.py,sha256=3cVKHUNzkIPnN2bvx7l5sia7Zc5poXS8lKOJlowXyLA,21088
4
4
  rowan/constants.py,sha256=emCH4m9OL2Hm5E-6mJGM_FgzrK_JrZT-FiKJ6pMNQ4Y,84
5
5
  rowan/folder.py,sha256=NkimVeHho9nwRXeS87U1tivEVL-1gL2Vqfz1fJ6XpNQ,9222
6
- rowan/molecule.py,sha256=MppZLHUAHzLCaIZtAbr2tpEULt5yRUR1B5npgFISCbE,10030
6
+ rowan/molecule.py,sha256=KQJhbNF2vmR8okBduXVqG7qG3LXbABLKHanpNhA-0TY,10003
7
7
  rowan/project.py,sha256=Wy3VvhwIMIumAZD2s7hPk8jj4bAPHMDNvsqU23RRqFo,4598
8
- rowan/protein.py,sha256=Ma2tBFF52Rb-ME5vZy5M5juMlmphQVQRL0Q1EBvBeZg,14761
8
+ rowan/protein.py,sha256=jyOM6g5eQH6KO8Eq07AiYBv2vZsGfbNOdtNOb2NWHFc,14799
9
9
  rowan/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  rowan/types.py,sha256=rCAnUlCsemyBK9Bbus0pL-THoqNqJIQHaMoDferIfFU,471
11
11
  rowan/user.py,sha256=Tnwz1-u_92ACt1xATQegtMj3FcosFsAG4m-4YuAkiyg,5955
12
12
  rowan/utils.py,sha256=c1s6Ze-OqLtfvrD23OV60otskejmj-CD88nNf8_nFcw,3636
13
13
  rowan/rowan_rdkit/__init__.py,sha256=EATX2VRzywzKxqkpCUMTf7RNQLkWsfi5VcCNDW6EIiw,503
14
14
  rowan/rowan_rdkit/chem_utils.py,sha256=ZWdLziT59Qr5JzjvV789CAyRq0m5JIawsOP4RxUbQQA,35529
15
- rowan/workflows/__init__.py,sha256=o2fN6V10mWt82QPr1UlbkyHzc2vtoIbkoiFZF2PgYow,4257
15
+ rowan/workflows/__init__.py,sha256=UTkqcsqtANh9TtaYXwOSYmTOvzR9ucQ_xhDupAFHROI,4351
16
16
  rowan/workflows/admet.py,sha256=0_wIwXXLfHF-3kgGx_1EM1ljjaYHLeEijJ-GbMYxpL8,2904
17
17
  rowan/workflows/analogue_docking.py,sha256=LJpbbaug0tZ9Cg-m0b7EgGH5hJ5894fHOC16Wefx7mE,9206
18
18
  rowan/workflows/base.py,sha256=eLGyzTc9NpXBGC-FRjsaUwKP6RluWrz0ipDZ4jDY_jc,30103
@@ -24,7 +24,7 @@ rowan/workflows/constants.py,sha256=el8jWE9gnGTLNWn5_n_V0H362vIRneOqgy7BOQ8CScg,
24
24
  rowan/workflows/descriptors.py,sha256=rGrNca6kA4SzX5BAOjP6rE91MOLTvCWSYKF_LW2Z0y4,2963
25
25
  rowan/workflows/docking.py,sha256=wmE7QJu1uDHBDynTT1XesXXAZtpB6xLjZUKsHOQyCcU,7386
26
26
  rowan/workflows/double_ended_ts_search.py,sha256=abBblMkshhbzq5UTwIf-ovNFxY8Ltp2O-bGu_plkI58,7806
27
- rowan/workflows/electronic_properties.py,sha256=AVVtpIIO82GRETHbemCLI8tqM7QHmr7XrGbrQ_YB5w4,7108
27
+ rowan/workflows/electronic_properties.py,sha256=2L0BUvhx0iT0k4gQf7hbceCpatznT2xui7rs6lpME7k,7564
28
28
  rowan/workflows/fukui.py,sha256=wLimH3QmorSpvkovRPlI91VuxHG4J91F2EcLYqg3eP0,5112
29
29
  rowan/workflows/hydrogen_bond_donor_acceptor_strength.py,sha256=WWiEK_GlumIEgTTOaqw-Y5gPDkRkaePWcIjTdIocrPc,4916
30
30
  rowan/workflows/interaction_energy_decomposition.py,sha256=Kjwkb-pviFSFIIZNjMb9i8nAkdKrbjFftmG_lkYtE40,6120
@@ -35,7 +35,8 @@ rowan/workflows/membrane_permeability.py,sha256=oIDmB8qF_K_Kesv7o_FiljAk4dpptEeO
35
35
  rowan/workflows/msa.py,sha256=V3B1SyWPR8MT306hh9W-T9JTpi_E-XgAIeF9yRQZ7tI,5075
36
36
  rowan/workflows/multistage_optimization.py,sha256=HFVx8mnHxG97pDYyL6eOhNGmESqTxaKNgUdwrFpFUJ0,6456
37
37
  rowan/workflows/nmr.py,sha256=hergJdsiawKj7iV-jHxDOS03n_EnZcaCIt_ZTl34-JY,5183
38
- rowan/workflows/pka.py,sha256=YAnFq1zyJO3j9rfYCYyrl-C_o8uaFTpCqoldqiP7o1k,8349
38
+ rowan/workflows/pka.py,sha256=TCFSE5HI5JLPslKdbUvJe4IxrVaLExrI_3PnDfXtxTw,8691
39
+ rowan/workflows/pocket_detection.py,sha256=aGHY0puxekp4c4nsNYHcvKCe1fsetygL04BcSvNFvE8,3864
39
40
  rowan/workflows/pose_analysis_md.py,sha256=UvotLhWv0_VAkKteZboOutDry7l-Zt1K6_SBx3EXqgM,9530
40
41
  rowan/workflows/protein_binder_design.py,sha256=J-9NSbRLdHb6JQRhY_vq43HlHCDCiQqrkOZUCAF-2dk,8604
41
42
  rowan/workflows/protein_cofolding.py,sha256=1R29XjAVjWHyelGG-mylP2GIamZbLCQKaaaFsCAnYgI,13012
@@ -49,7 +50,7 @@ rowan/workflows/solvent_dependent_conformers.py,sha256=ovvnhCE4xlkpdhccLHEq7oBJR
49
50
  rowan/workflows/spin_states.py,sha256=GZgBJPO6_ds9el4b7wbigIZ5213Z9DwXhokczJ5NDhs,7122
50
51
  rowan/workflows/strain.py,sha256=r0tlZoUlAslAiF7dPTpa9WlQFUAKyVjZ19zASjSS8Hs,6339
51
52
  rowan/workflows/tautomer_search.py,sha256=aqwXoj0ffWsb5gbvzfz_bpx5ifIfR_K07fbdWhU62Ko,5820
52
- rowan_python-3.0.5.dist-info/METADATA,sha256=0wZHFNgNRDm1DwrdDVJJh1Xu05Xm8A31whsYlwCSVWM,1600
53
- rowan_python-3.0.5.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
54
- rowan_python-3.0.5.dist-info/licenses/LICENSE,sha256=i05z7xEhyrg6f8j0lR3XYjShnF-MJGFQ-DnpsZ8yiVI,1084
55
- rowan_python-3.0.5.dist-info/RECORD,,
53
+ rowan_python-3.0.7.dist-info/METADATA,sha256=-sirW_Q74BeqsjNRR4wAWYoV8ebpuNLzc6-8FrgOKRs,1600
54
+ rowan_python-3.0.7.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
55
+ rowan_python-3.0.7.dist-info/licenses/LICENSE,sha256=i05z7xEhyrg6f8j0lR3XYjShnF-MJGFQ-DnpsZ8yiVI,1084
56
+ rowan_python-3.0.7.dist-info/RECORD,,