stjames 0.0.64__tar.gz → 0.0.65__tar.gz

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.

Potentially problematic release.


This version of stjames might be problematic. Click here for more details.

Files changed (79) hide show
  1. {stjames-0.0.64/stjames.egg-info → stjames-0.0.65}/PKG-INFO +1 -1
  2. {stjames-0.0.64 → stjames-0.0.65}/pyproject.toml +1 -1
  3. {stjames-0.0.64 → stjames-0.0.65}/stjames/atomium_stjames/mmcif.py +6 -4
  4. {stjames-0.0.64 → stjames-0.0.65}/stjames/molecule.py +1 -0
  5. {stjames-0.0.64 → stjames-0.0.65}/stjames/pdb.py +6 -0
  6. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/__init__.py +3 -0
  7. stjames-0.0.65/stjames/workflows/admet.py +39 -0
  8. stjames-0.0.65/stjames/workflows/ion_mobility.py +36 -0
  9. stjames-0.0.65/stjames/workflows/macropka.py +72 -0
  10. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/scan.py +21 -3
  11. {stjames-0.0.64 → stjames-0.0.65/stjames.egg-info}/PKG-INFO +1 -1
  12. {stjames-0.0.64 → stjames-0.0.65}/stjames.egg-info/SOURCES.txt +2 -0
  13. {stjames-0.0.64 → stjames-0.0.65}/tests/test_pdb.py +62 -1
  14. stjames-0.0.64/stjames/workflows/admet.py +0 -18
  15. {stjames-0.0.64 → stjames-0.0.65}/LICENSE +0 -0
  16. {stjames-0.0.64 → stjames-0.0.65}/README.md +0 -0
  17. {stjames-0.0.64 → stjames-0.0.65}/setup.cfg +0 -0
  18. {stjames-0.0.64 → stjames-0.0.65}/stjames/__init__.py +0 -0
  19. {stjames-0.0.64 → stjames-0.0.65}/stjames/_deprecated_solvent_settings.py +0 -0
  20. {stjames-0.0.64 → stjames-0.0.65}/stjames/atom.py +0 -0
  21. {stjames-0.0.64 → stjames-0.0.65}/stjames/atomium_stjames/__init__.py +0 -0
  22. {stjames-0.0.64 → stjames-0.0.65}/stjames/atomium_stjames/data.py +0 -0
  23. {stjames-0.0.64 → stjames-0.0.65}/stjames/atomium_stjames/pdb.py +0 -0
  24. {stjames-0.0.64 → stjames-0.0.65}/stjames/atomium_stjames/utilities.py +0 -0
  25. {stjames-0.0.64 → stjames-0.0.65}/stjames/base.py +0 -0
  26. {stjames-0.0.64 → stjames-0.0.65}/stjames/basis_set.py +0 -0
  27. {stjames-0.0.64 → stjames-0.0.65}/stjames/calculation.py +0 -0
  28. {stjames-0.0.64 → stjames-0.0.65}/stjames/compute_settings.py +0 -0
  29. {stjames-0.0.64 → stjames-0.0.65}/stjames/constraint.py +0 -0
  30. {stjames-0.0.64 → stjames-0.0.65}/stjames/correction.py +0 -0
  31. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/__init__.py +0 -0
  32. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/bragg_radii.json +0 -0
  33. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/elements.py +0 -0
  34. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/isotopes.json +0 -0
  35. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/nist_isotopes.json +0 -0
  36. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/read_nist_isotopes.py +0 -0
  37. {stjames-0.0.64 → stjames-0.0.65}/stjames/data/symbol_element.json +0 -0
  38. {stjames-0.0.64 → stjames-0.0.65}/stjames/diis_settings.py +0 -0
  39. {stjames-0.0.64 → stjames-0.0.65}/stjames/grid_settings.py +0 -0
  40. {stjames-0.0.64 → stjames-0.0.65}/stjames/int_settings.py +0 -0
  41. {stjames-0.0.64 → stjames-0.0.65}/stjames/message.py +0 -0
  42. {stjames-0.0.64 → stjames-0.0.65}/stjames/method.py +0 -0
  43. {stjames-0.0.64 → stjames-0.0.65}/stjames/mode.py +0 -0
  44. {stjames-0.0.64 → stjames-0.0.65}/stjames/opt_settings.py +0 -0
  45. {stjames-0.0.64 → stjames-0.0.65}/stjames/periodic_cell.py +0 -0
  46. {stjames-0.0.64 → stjames-0.0.65}/stjames/py.typed +0 -0
  47. {stjames-0.0.64 → stjames-0.0.65}/stjames/scf_settings.py +0 -0
  48. {stjames-0.0.64 → stjames-0.0.65}/stjames/settings.py +0 -0
  49. {stjames-0.0.64 → stjames-0.0.65}/stjames/solvent.py +0 -0
  50. {stjames-0.0.64 → stjames-0.0.65}/stjames/status.py +0 -0
  51. {stjames-0.0.64 → stjames-0.0.65}/stjames/task.py +0 -0
  52. {stjames-0.0.64 → stjames-0.0.65}/stjames/thermochem_settings.py +0 -0
  53. {stjames-0.0.64 → stjames-0.0.65}/stjames/types.py +0 -0
  54. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/basic_calculation.py +0 -0
  55. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/bde.py +0 -0
  56. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/conformer.py +0 -0
  57. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/conformer_search.py +0 -0
  58. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/descriptors.py +0 -0
  59. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/docking.py +0 -0
  60. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/electronic_properties.py +0 -0
  61. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/fukui.py +0 -0
  62. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/hydrogen_bond_basicity.py +0 -0
  63. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/irc.py +0 -0
  64. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/molecular_dynamics.py +0 -0
  65. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/multistage_opt.py +0 -0
  66. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/pka.py +0 -0
  67. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/redox_potential.py +0 -0
  68. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/solubility.py +0 -0
  69. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/spin_states.py +0 -0
  70. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/tautomer.py +0 -0
  71. {stjames-0.0.64 → stjames-0.0.65}/stjames/workflows/workflow.py +0 -0
  72. {stjames-0.0.64 → stjames-0.0.65}/stjames.egg-info/dependency_links.txt +0 -0
  73. {stjames-0.0.64 → stjames-0.0.65}/stjames.egg-info/requires.txt +0 -0
  74. {stjames-0.0.64 → stjames-0.0.65}/stjames.egg-info/top_level.txt +0 -0
  75. {stjames-0.0.64 → stjames-0.0.65}/tests/test_constraints.py +0 -0
  76. {stjames-0.0.64 → stjames-0.0.65}/tests/test_from_extxyz.py +0 -0
  77. {stjames-0.0.64 → stjames-0.0.65}/tests/test_molecule.py +0 -0
  78. {stjames-0.0.64 → stjames-0.0.65}/tests/test_rounding.py +0 -0
  79. {stjames-0.0.64 → stjames-0.0.65}/tests/test_settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: stjames
3
- Version: 0.0.64
3
+ Version: 0.0.65
4
4
  Summary: standardized JSON atom/molecule encoding scheme
5
5
  Author-email: Corin Wagen <corin@rowansci.com>
6
6
  Project-URL: Homepage, https://github.com/rowansci/stjames
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "stjames"
3
- version = "0.0.64"
3
+ version = "0.0.65"
4
4
  description = "standardized JSON atom/molecule encoding scheme"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -516,7 +516,7 @@ def add_atom_to_polymer(atom: dict[str, Any], aniso: dict[int, Any], model: dict
516
516
  try:
517
517
  model["polymer"][mol_id]["residues"][res_id] = {
518
518
  "name": name,
519
- "full_name": names.get(name),
519
+ "full_name": names.get(name).upper() if names.get(name) is not None else None, # type: ignore [union-attr]
520
520
  "atoms": {int(atom["id"]): atom_dict_to_atom_dict(atom, aniso)},
521
521
  "number": len(model["polymer"][mol_id]["residues"]) + 1,
522
522
  }
@@ -530,7 +530,7 @@ def add_atom_to_polymer(atom: dict[str, Any], aniso: dict[int, Any], model: dict
530
530
  "name": name,
531
531
  "atoms": {int(atom["id"]): atom_dict_to_atom_dict(atom, aniso)},
532
532
  "number": 1,
533
- "full_name": names.get(name),
533
+ "full_name": names.get(name).upper() if names.get(name) is not None else None, # type: ignore [union-attr]
534
534
  }
535
535
  },
536
536
  }
@@ -547,6 +547,8 @@ def add_atom_to_non_polymer(atom: dict[str, Any], aniso: dict[int, Any], model:
547
547
  :param names: lookup dictionary for full name information
548
548
  """
549
549
  mol_id = make_residue_id(atom)
550
+ if mol_type == "non-polymer":
551
+ mol_type = "non_polymer"
550
552
 
551
553
  try:
552
554
  model[mol_type][mol_id]["atoms"][int(atom["id"])] = atom_dict_to_atom_dict(atom, aniso)
@@ -554,7 +556,7 @@ def add_atom_to_non_polymer(atom: dict[str, Any], aniso: dict[int, Any], model:
554
556
  name = atom["auth_comp_id"]
555
557
  model[mol_type][mol_id] = {
556
558
  "name": name,
557
- "full_name": names.get(name),
559
+ "full_name": names.get(name).upper() if names.get(name) is not None and names.get(name).lower() != "water" else None, # type: ignore [union-attr]
558
560
  "internal_id": atom["label_asym_id"],
559
561
  "polymer": atom["auth_asym_id"],
560
562
  "atoms": {int(atom["id"]): atom_dict_to_atom_dict(atom, aniso)},
@@ -644,7 +646,7 @@ def atom_dict_to_atom_dict(d: dict[str, Any], aniso_dict: dict[int, Any]) -> dic
644
646
  "bvalue": d.get("B_iso_or_equiv"),
645
647
  "charge": d.get(charge, 0) if d.get(charge) != "?" else 0,
646
648
  "alt_loc": d.get("label_alt_id") if d.get("label_alt_id") != "." else None,
647
- "anisotropy": aniso_dict.get(int(d["id"]), [0, 0, 0, 0, 0, 0]),
649
+ "anisotropy": aniso_dict.get(int(d["id"]), None),
648
650
  "is_hetatm": d.get("group_PDB", "ATOM") == "HETATM",
649
651
  }
650
652
 
@@ -34,6 +34,7 @@ class VibrationalMode(Base):
34
34
  reduced_mass: Annotated[float, AfterValidator(round_float(3))] # amu
35
35
  force_constant: Annotated[float, AfterValidator(round_float(3))] # mDyne/Å
36
36
  displacements: Annotated[Vector3DPerAtom, AfterValidator(round_vector3d_per_atom(6))] # Å
37
+ ir_intensity: Annotated[Optional[float], AfterValidator(round_optional_float(3))] = None # km/mol
37
38
 
38
39
 
39
40
  class Molecule(Base):
@@ -204,6 +204,12 @@ def fetch_pdb(code: str) -> PDB:
204
204
  return PDB.model_validate(astj.fetch(code, data_dict=True))
205
205
 
206
206
 
207
+ def fetch_pdb_from_mmcif(code: str) -> PDB:
208
+ """Fetch a pdb from the Protein Data Bank."""
209
+ code += ".cif"
210
+ return PDB.model_validate(astj.fetch(code, data_dict=True))
211
+
212
+
207
213
  def pdb_from_pdb_filestring(pdb: str) -> PDB:
208
214
  """Read a PDB from a string."""
209
215
  return PDB.model_validate(pdb_dict_to_data_dict(pdb_string_to_pdb_dict(pdb)))
@@ -12,6 +12,7 @@ from .docking import *
12
12
  from .electronic_properties import *
13
13
  from .fukui import *
14
14
  from .hydrogen_bond_basicity import *
15
+ from .ion_mobility import *
15
16
  from .irc import *
16
17
  from .molecular_dynamics import *
17
18
  from .multistage_opt import *
@@ -34,6 +35,7 @@ WORKFLOW_NAME = Literal[
34
35
  "electronic_properties",
35
36
  "fukui",
36
37
  "hydrogen_bond_basicity",
38
+ "ion_mobility",
37
39
  "irc",
38
40
  "molecular_dynamics",
39
41
  "multistage_opt",
@@ -56,6 +58,7 @@ WORKFLOW_MAPPING: dict[WORKFLOW_NAME, Workflow] = {
56
58
  "electronic_properties": ElectronicPropertiesWorkflow, # type: ignore [dict-item]
57
59
  "fukui": FukuiIndexWorkflow, # type: ignore [dict-item]
58
60
  "hydrogen_bond_basicity": HydrogenBondBasicityWorkflow, # type: ignore [dict-item]
61
+ "ion_mobility": IonMobilityWorkflow, # type: ignore [dict-item]
59
62
  "irc": IRCWorkflow, # type: ignore [dict-item]
60
63
  "molecular_dynamics": MolecularDynamicsWorkflow, # type: ignore [dict-item]
61
64
  "multistage_opt": MultiStageOptWorkflow, # type: ignore [dict-item]
@@ -0,0 +1,39 @@
1
+ """ADME-Tox property prediction workflow."""
2
+
3
+ import warnings
4
+ from typing import Self
5
+
6
+ from pydantic import model_validator
7
+
8
+ from ..molecule import Molecule
9
+ from .workflow import MoleculeWorkflow, SMILESWorkflow
10
+
11
+
12
+ class ADMETWorkflow(SMILESWorkflow, MoleculeWorkflow):
13
+ """
14
+ A workflow for predicting ADME-Tox properties.
15
+
16
+ Inherited:
17
+ :param initial_smiles: SMILES string of molecule (mutually exclusive with initial_molecule)
18
+ :param initial_molecule: Molecule of interest (deprecated)
19
+ :param mode: Mode for workflow (currently unused)
20
+
21
+ New:
22
+ :param properties: predicted properties
23
+ """
24
+
25
+ initial_smiles: str = ""
26
+ initial_molecule: Molecule | None = None # type: ignore [assignment] # Deprecated
27
+ properties: dict[str, float | int] | None = None
28
+
29
+ @model_validator(mode="after")
30
+ def validate_mol_input(self) -> Self:
31
+ """Ensure that only one of initial_molecule or initial_smiles is set."""
32
+
33
+ if not (bool(self.initial_smiles) ^ bool(self.initial_molecule)):
34
+ raise ValueError("Can only set one of initial_molecule should and initial_smiles")
35
+
36
+ if self.initial_molecule is not None:
37
+ warnings.warn(DeprecationWarning("initial_molecule is deprecated. Use initial_smiles instead."))
38
+
39
+ return self
@@ -0,0 +1,36 @@
1
+ """Ion mobility workflow."""
2
+
3
+ from ..types import UUID
4
+ from .workflow import MoleculeWorkflow
5
+
6
+
7
+ class IonMobilityWorkflow(MoleculeWorkflow):
8
+ """
9
+ Workflow for calculating hydrogen bond basicity.
10
+
11
+ Inherited:
12
+ :param initial_molecule: Molecule of interest
13
+ :param mode: Mode for workflow (currently unused)
14
+
15
+ New:
16
+ :param do_csearch: whether to perform a conformational search
17
+ :param do_optimization: whether to perform an optimization
18
+
19
+ Results:
20
+ :param conformer_ccs: the collision cross section (Å**2) per conformer
21
+ :param conformer_ccs_stdev: the uncertainty in the same
22
+ :param conformer_weights: the Boltzmann weights at RT
23
+ :param average_ccs: the Boltzmann-weighted CCS for the ensemble
24
+ :param average_ccs_stdev: the uncertainty in the same
25
+ """
26
+
27
+ do_csearch: bool = True
28
+ do_optimization: bool = True
29
+ conformers: list[UUID] = []
30
+
31
+ conformer_ccs: list[float] = []
32
+ conformer_ccs_stdev: list[float] = []
33
+ boltzmann_weights: list[float] = []
34
+
35
+ average_ccs: float | None = None
36
+ average_ccs_stdev: float | None = None
@@ -0,0 +1,72 @@
1
+ """pKa workflow."""
2
+
3
+ from typing import Annotated, Self
4
+
5
+ from pydantic import AfterValidator, model_validator
6
+
7
+ from ..base import Base, round_float
8
+ from ..types import round_list
9
+ from .workflow import SMILESWorkflow
10
+
11
+
12
+ class MacropKaMicrostate(Base):
13
+ """
14
+ A microstate for pKa calculations.
15
+
16
+ :param smiles: SMILES string for this conformer
17
+ :param energy: free energy of this conformer
18
+ :param charge: the total charge
19
+ """
20
+
21
+ smiles: str
22
+ energy: Annotated[float, AfterValidator(round_float(3))] # free energy
23
+ charge: int
24
+
25
+
26
+ class MacropKaValue(Base):
27
+ """
28
+ Represents a change in pKa.
29
+
30
+ :param initial_charge: the charge of the initial state
31
+ :param final_charge: the charge of the final state
32
+ :param pKa: the pKa for the transition
33
+ """
34
+
35
+ initial_charge: int
36
+ final_charge: int
37
+ pKa: Annotated[float, AfterValidator(round_float(3))]
38
+
39
+
40
+ class MacropKaWorkflow(SMILESWorkflow):
41
+ """
42
+ Workflow for calculating pKa.
43
+
44
+ Inherited:
45
+ :param initial_smiles:
46
+
47
+ New:
48
+ :param temperature: the temperature, in K
49
+ :param min_pH: for precomputed microstate weights
50
+ :param max_pH: for precomputed microstate weights
51
+
52
+ Results:
53
+ :param microstates: microstates
54
+ :param pKa_values: macroscopic pKa values
55
+ :param microstate_weights_by_pH: precompute the % of different microstates
56
+ """
57
+
58
+ temperature: Annotated[float, AfterValidator(round_float(3))] = 298.0
59
+ min_pH: Annotated[float, AfterValidator(round_float(3))] = 0.0
60
+ max_pH: Annotated[float, AfterValidator(round_float(3))] = 14.0
61
+
62
+ microstates: list[MacropKaMicrostate] = []
63
+ pKa_values: list[MacropKaValue] = []
64
+ microstate_weights_by_pH: dict[float, Annotated[list[float], AfterValidator(round_list(6))]] = {}
65
+
66
+ @model_validator(mode="after")
67
+ def check_weights(self) -> Self:
68
+ for weights in self.microstate_weights_by_pH.values():
69
+ if len(weights) != len(self.microstates):
70
+ raise ValueError("Length of microstate weights doesn't match!")
71
+
72
+ return self
@@ -4,7 +4,7 @@ from typing import Annotated
4
4
 
5
5
  import numpy as np
6
6
  from numpy.typing import NDArray
7
- from pydantic import AfterValidator
7
+ from pydantic import AfterValidator, field_validator
8
8
 
9
9
  from ..base import Base, round_optional_float
10
10
  from ..molecule import Molecule
@@ -62,15 +62,33 @@ class ScanWorkflow(MoleculeWorkflow):
62
62
  :param mode: Mode for workflow (currently unused)
63
63
 
64
64
  New:
65
- :param scan_settings: information about what coordinate to scan
65
+ :param scan_settings: what coordinate(s) to scan; if more than one, all will be performed simultaneously and should have the same number of steps
66
+ :param scan_settings_2d: what additional coordinate(s) to scan; makes a grid with `scan_settings`
67
+ :param wavefront propagation: whether to use wavefront propagation (10.1063/5.0009232) for more expensive but smoother scans
66
68
  :param calc_settings: settings for the calculation
67
69
  :param calc_engine: engine to use for the calculation
68
70
  :param scan_points: points along the scan
69
71
  """
70
72
 
71
- scan_settings: ScanSettings
73
+ scan_settings: ScanSettings | list[ScanSettings]
74
+ scan_settings_2d: ScanSettings | list[ScanSettings] = []
72
75
  calc_settings: Settings
73
76
  calc_engine: str
74
77
 
78
+ wavefront_propagation: bool = True
79
+
75
80
  # UUIDs of scan points
76
81
  scan_points: list[UUID | None] = []
82
+
83
+ @field_validator("scan_settings", "scan_settings_2d", mode="after")
84
+ @classmethod
85
+ def validate_scan_settings(cls, val: ScanSettings | list[ScanSettings]) -> list[ScanSettings]:
86
+ """Ensure that scan_settings is a list, and that every list item has the same number of steps."""
87
+ if isinstance(val, ScanSettings):
88
+ val = [val]
89
+
90
+ for ss in val:
91
+ if ss.num != val[0].num:
92
+ raise ValueError("Concerted scan settings must have same number of steps!")
93
+
94
+ return val
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: stjames
3
- Version: 0.0.64
3
+ Version: 0.0.65
4
4
  Summary: standardized JSON atom/molecule encoding scheme
5
5
  Author-email: Corin Wagen <corin@rowansci.com>
6
6
  Project-URL: Homepage, https://github.com/rowansci/stjames
@@ -56,7 +56,9 @@ stjames/workflows/docking.py
56
56
  stjames/workflows/electronic_properties.py
57
57
  stjames/workflows/fukui.py
58
58
  stjames/workflows/hydrogen_bond_basicity.py
59
+ stjames/workflows/ion_mobility.py
59
60
  stjames/workflows/irc.py
61
+ stjames/workflows/macropka.py
60
62
  stjames/workflows/molecular_dynamics.py
61
63
  stjames/workflows/multistage_opt.py
62
64
  stjames/workflows/pka.py
@@ -1,6 +1,16 @@
1
1
  from pytest import mark
2
2
 
3
- from stjames.pdb import PDB, fetch_pdb, pdb_from_mmcif_filestring, pdb_from_pdb_filestring, pdb_object_to_pdb_filestring
3
+ from stjames.pdb import (
4
+ PDB,
5
+ PDBDescription,
6
+ PDBExperiment,
7
+ PDBModel,
8
+ fetch_pdb,
9
+ fetch_pdb_from_mmcif,
10
+ pdb_from_mmcif_filestring,
11
+ pdb_from_pdb_filestring,
12
+ pdb_object_to_pdb_filestring,
13
+ )
4
14
 
5
15
 
6
16
  def test_1ema() -> None:
@@ -8,6 +18,14 @@ def test_1ema() -> None:
8
18
  fetch_pdb("1EMA")
9
19
 
10
20
 
21
+ def test_8qvy() -> None:
22
+ """
23
+ Human GABAA receptor
24
+ Not availble as a .pdb
25
+ """
26
+ fetch_pdb_from_mmcif("8VQY")
27
+
28
+
11
29
  def test_read_pdb_filestring() -> None:
12
30
  """Rest reading of a pdb string."""
13
31
  with open("tests/data/1ema.pdb") as f:
@@ -77,3 +95,46 @@ def test_from_pdb_to_pdb_1ema() -> None:
77
95
  pdb2 = pdb_from_pdb_filestring(filestring)
78
96
 
79
97
  assert pdb == pdb2
98
+
99
+ def mmcif_author_format_to_pdb_format(authors: list[str]) -> list[str]:
100
+ return [f"{last.upper()}{first.upper()}" for first, last in
101
+ (author.split(", ") for author in authors)]
102
+
103
+ def compare_descriptions_mmcif_and_pdb(mmcif_description: PDBDescription, pdb_description: PDBDescription) -> bool:
104
+ return (
105
+ mmcif_description.code == pdb_description.code and
106
+ mmcif_description.title == pdb_description.title and
107
+ mmcif_author_format_to_pdb_format(mmcif_description.authors) == (pdb_description.authors) and
108
+ mmcif_description.classification == pdb_description.classification and
109
+ mmcif_description.deposition_date == pdb_description.deposition_date and
110
+ sorted(mmcif_description.keywords) == sorted(pdb_description.keywords)
111
+ )
112
+
113
+ def compare_experiments_mmcif_and_pdb(mmcif_experiment: PDBExperiment, pdb_experiment: PDBExperiment) -> bool:
114
+ return (
115
+ mmcif_experiment.expression_system.upper() == pdb_experiment.expression_system and # type: ignore [union-attr]
116
+ mmcif_experiment.missing_residues == pdb_experiment.missing_residues and
117
+ mmcif_experiment.source_organism.upper() == pdb_experiment.source_organism and # type: ignore [union-attr]
118
+ mmcif_experiment.technique == pdb_experiment.technique
119
+ )
120
+
121
+ def compare_models_mmcif_and_pdb(mmcif_models: list[PDBModel], pdb_models: list[PDBModel]) -> bool:
122
+ for i in range(len(mmcif_models)):
123
+ assert mmcif_models[i].polymer == pdb_models[i].polymer
124
+ assert mmcif_models[i].non_polymer == pdb_models[i].non_polymer
125
+ assert mmcif_models[i].branched == pdb_models[i].branched
126
+ return True
127
+
128
+ def test_from_mmcif_to_pdb_1ema() -> None:
129
+ with open("tests/data/1ema.cif") as f:
130
+ mmcif_data = f.read()
131
+
132
+ with open("tests/data/1ema.pdb") as f:
133
+ pdb_data = f.read()
134
+ mmcif_1ema = pdb_from_mmcif_filestring(mmcif_data)
135
+ pdb_1ema = pdb_from_pdb_filestring(pdb_data)
136
+
137
+ assert compare_descriptions_mmcif_and_pdb(mmcif_1ema.description, pdb_1ema.description)
138
+ assert compare_experiments_mmcif_and_pdb(mmcif_1ema.experiment, pdb_1ema.experiment)
139
+ assert mmcif_1ema.quality == pdb_1ema.quality
140
+ assert compare_models_mmcif_and_pdb(mmcif_1ema.models, pdb_1ema.models)
@@ -1,18 +0,0 @@
1
- """ADME-Tox property prediction workflow."""
2
-
3
- from .workflow import MoleculeWorkflow
4
-
5
-
6
- class ADMETWorkflow(MoleculeWorkflow):
7
- """
8
- A workflow for predicting ADME-Tox properties.
9
-
10
- Inherited:
11
- :param initial_molecule: Molecule of interest
12
- :param mode: Mode for workflow (currently unused)
13
-
14
- New:
15
- :param properties: predicted properties
16
- """
17
-
18
- properties: dict[str, float | int] | None = None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes