Skip to content

Commit

Permalink
delegate subclass-specific _decode_object
Browse files Browse the repository at this point in the history
  • Loading branch information
rwxayheee committed Dec 19, 2024
1 parent e2165f8 commit 5c31d03
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 98 deletions.
2 changes: 2 additions & 0 deletions meeko/cli/mk_prepare_receptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
from meeko import PDBQTMolecule
from meeko import RDKitMolCreate
from meeko import MoleculePreparation
from meeko import MoleculeSetup
from meeko import ResidueChemTemplates
from meeko import PDBQTWriterLegacy
from meeko import Polymer
from meeko import PolymerCreationError
from meeko import reactive_typer
from meeko import get_reactive_config
from meeko import gridbox
from meeko import __file__ as pkg_init_path
from rdkit import Chem

try:
Expand Down
85 changes: 25 additions & 60 deletions meeko/molsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,25 @@ class Atom(BaseJSONParsable):

is_dummy: bool = False
is_pseudo_atom: bool = False

# region JSON-interchange functions
@classmethod
def json_encoder(cls, obj: "Atom") -> Optional[dict[str, Any]]:

return {
"index": obj.index,
"pdbinfo": obj.pdbinfo,
"charge": obj.charge,
"coord": obj.coord.tolist(), # converts coord from numpy array to lists
"atomic_num": obj.atomic_num,
"atom_type": obj.atom_type,
"is_ignore": obj.is_ignore,
"graph": obj.graph,
"interaction_vectors": [v.tolist() for v in obj.interaction_vectors],
"is_dummy": obj.is_dummy,
"is_pseudo_atom": obj.is_pseudo_atom,
}

# Keys to check for deserialized JSON
expected_json_keys = {
"index",
Expand All @@ -221,13 +239,7 @@ class Atom(BaseJSONParsable):
}

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Constructs an atom object from the provided keys.
index = obj["index"]
Expand Down Expand Up @@ -255,23 +267,7 @@ def json_decoder(cls, obj: dict[str, Any]):
is_pseudo_atom,
)
return output_atom

@classmethod
def json_encoder(cls, obj: "Atom") -> Optional[dict[str, Any]]:

return {
"index": obj.index,
"pdbinfo": obj.pdbinfo,
"charge": obj.charge,
"coord": obj.coord.tolist(), # converts coord from numpy array to lists
"atomic_num": obj.atomic_num,
"atom_type": obj.atom_type,
"is_ignore": obj.is_ignore,
"graph": obj.graph,
"interaction_vectors": [v.tolist() for v in obj.interaction_vectors],
"is_dummy": obj.is_dummy,
"is_pseudo_atom": obj.is_pseudo_atom,
}
# endregion


@dataclass
Expand Down Expand Up @@ -318,13 +314,7 @@ def get_bond_id(idx1: int, idx2: int):
return idx_min, idx_max

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Constructs a bond object from the provided keys.
index1 = obj["index1"]
Expand All @@ -351,13 +341,7 @@ class Ring(BaseJSONParsable):
expected_json_keys = {"ring_id"}

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Constructs a Ring object from the provided keys.
ring_id = string_to_tuple(obj["ring_id"], int)
Expand Down Expand Up @@ -407,13 +391,7 @@ def copy(self):
return new_restraint

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Constructs a Restraint object from the provided keys.
atom_index = obj["atom_index"]
Expand Down Expand Up @@ -501,14 +479,7 @@ def __init__(self, name: str = None, is_sidechain: bool = False):
self.flexibility_model = None # from flexibility_model - from flexibility.py

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
# allows more keys in RDKitMoleculeSetup
if not cls.expected_json_keys.issubset(obj.keys()):
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Constructs a MoleculeSetup object and restores the expected attributes
name = obj["name"]
Expand Down Expand Up @@ -1573,13 +1544,7 @@ def __init__(self, name: str = None, is_sidechain: bool = False,


@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

try:

Expand Down
40 changes: 5 additions & 35 deletions meeko/polymer.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,13 +594,7 @@ def __init__(self, residue_templates, padders, ambiguous):
self.ambiguous = ambiguous

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Extracting the constructor args from the json representation and creating a ResidueChemTemplates instance
templates = {
Expand Down Expand Up @@ -973,13 +967,7 @@ def __init__(


@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Deserializes ResidueChemTemplates from the dict to use as an input, then constructs a Polymer object
# and sets its values using deserialized JSON values.
Expand Down Expand Up @@ -2135,13 +2123,7 @@ def _invert_mapping(mapping):
return inverted

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

try:
raw_rdkit_mol = rdkit_mol_from_json(obj["raw_rdkit_mol"])
Expand Down Expand Up @@ -2555,13 +2537,7 @@ def _check_target_mol(self, target_mol: Chem.Mol):
return False

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

return ResiduePadder(obj["rxn_smarts"], obj["adjacent_smarts"], obj["auto_blunt"])

Expand Down Expand Up @@ -2678,13 +2654,7 @@ def json_encoder(cls, obj: "ResidueTemplate") -> Optional[dict[str, Any]]:
return output_dict

@classmethod
def json_decoder(cls, obj: dict[str, Any]):

# avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if set(obj.keys()) != cls.expected_json_keys:
return obj
def _decode_object(cls, obj: dict[str, Any]):

# Converting ResidueTemplate init values that need conversion
deserialized_mol = rdkit_mol_from_json(obj["mol"])
Expand Down
17 changes: 14 additions & 3 deletions meeko/utils/jsonutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,23 @@ class BaseJSONParsable:
@classmethod
def json_encoder(cls, obj):
raise NotImplementedError("Subclasses must implement json_encoder.")

@classmethod
def json_decoder(cls, obj):
raise NotImplementedError("Subclasses must implement json_decoder.")
def _decode_object(cls, obj):
raise NotImplementedError("Subclasses must implement _decode_object.")

# Inheritable JSON Interchange Functions
@classmethod
def json_decoder(cls, obj: dict[str, Any]):
# Avoid using json_decoder as object_hook for nested objects
if not isinstance(obj, dict):
return obj
if not cls.expected_json_keys.issubset(obj.keys()):
return obj

# Delegate specific decoding logic to a subclass-defined method
return cls._decode_object(obj)

@classmethod
def from_json(cls, json_string: str):
try:
Expand Down

0 comments on commit 5c31d03

Please sign in to comment.