Skip to content

Commit

Permalink
Make ChemicalMetadata __repr__
Browse files Browse the repository at this point in the history
  • Loading branch information
CalebBell committed Nov 24, 2024
1 parent dd0b4c6 commit f239172
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 12 deletions.
51 changes: 45 additions & 6 deletions chemicals/identifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,46 @@ class ChemicalMetadata:

__slots__ = ('pubchemid', 'formula', 'MW', 'smiles', 'InChI', 'InChI_key',
'iupac_name', 'common_name', 'synonyms', 'CAS', '_charge')

def __repr__(self):
return (f"ChemicalMetadata(pubchemid={self.pubchemid!r}, "
f"CAS={self.CAS!r}, "
f"formula={self.formula!r}, "
f"MW={self.MW!r}, "
f"smiles={self.smiles!r}, "
f"InChI={self.InChI!r}, "
f"InChI_key={self.InChI_key!r}, "
f"iupac_name={self.iupac_name!r}, "
f"common_name={self.common_name!r}, "
f"synonyms={self.synonyms!r})")

def __eq__(self, other):
if self is other:
return True
return (self.pubchemid == other.pubchemid and
self.CAS == other.CAS and
self.formula == other.formula and
self.MW == other.MW and
self.smiles == other.smiles and
self.InChI == other.InChI and
self.InChI_key == other.InChI_key and
self.iupac_name == other.iupac_name and
self.common_name == other.common_name and
self.synonyms == other.synonyms)

def __hash__(self):
return hash((self.pubchemid,
self.CAS,
self.formula,
self.MW,
self.smiles,
self.InChI,
self.InChI_key,
self.iupac_name,
self.common_name,
tuple(self.synonyms)))

def __str__(self):
return (f'<ChemicalMetadata, name={self.common_name}, formula={self.formula}, smiles={self.smiles}, MW={self.MW:g}>')

@property
Expand Down Expand Up @@ -610,17 +649,17 @@ def search_chemical(ID, autoload=False, cache=True):
Examples
--------
>>> search_chemical('water')
>>> print(search_chemical('water'))
<ChemicalMetadata, name=water, formula=H2O, smiles=O, MW=18.0153>
>>> search_chemical('InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3')
>>> print(search_chemical('InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('CCCCCCCCCC')
>>> print(search_chemical('CCCCCCCCCC'))
<ChemicalMetadata, name=decane, formula=C10H22, smiles=CCCCCCCCCC, MW=142.282>
>>> search_chemical('InChIKey=LFQSCWFLJHTTHZ-UHFFFAOYSA-N')
>>> print(search_chemical('InChIKey=LFQSCWFLJHTTHZ-UHFFFAOYSA-N'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('pubchem=702')
>>> print(search_chemical('pubchem=702'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('O') # only elements can be specified by symbol
>>> print(search_chemical('O')) # only elements can be specified by symbol
<ChemicalMetadata, name=oxygen, formula=O, smiles=[O], MW=15.9994>
"""
if cache and ID in chemical_search_cache:
Expand Down
12 changes: 6 additions & 6 deletions docs/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,17 +152,17 @@ inputs may be specified as

Some sample queries illustrating the topic:

>>> search_chemical('water')
>>> print(search_chemical('water'))
<ChemicalMetadata, name=water, formula=H2O, smiles=O, MW=18.0153>
>>> search_chemical('InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3')
>>> print(search_chemical('InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('CCCCCCCCCC')
>>> print(search_chemical('CCCCCCCCCC'))
<ChemicalMetadata, name=decane, formula=C10H22, smiles=CCCCCCCCCC, MW=142.282>
>>> search_chemical('InChIKey=LFQSCWFLJHTTHZ-UHFFFAOYSA-N')
>>> print(search_chemical('InChIKey=LFQSCWFLJHTTHZ-UHFFFAOYSA-N'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('pubchem=702')
>>> print(search_chemical('pubchem=702'))
<ChemicalMetadata, name=ethanol, formula=C2H6O, smiles=CCO, MW=46.0684>
>>> search_chemical('O') # only elements can be specified by symbol
>>> print(search_chemical('O')) # only elements can be specified by symbol
<ChemicalMetadata, name=oxygen, formula=O, smiles=[O], MW=15.9994>


Expand Down
68 changes: 68 additions & 0 deletions tests/test_identifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
CAS_from_any,
CAS_to_int,
ChemicalMetadataDB,
ChemicalMetadata,
IDs_to_CASs,
check_CAS,
common_mixtures,
Expand Down Expand Up @@ -1448,6 +1449,73 @@ def test_sorted_CAS_key():



def test_ChemicalMetadata_basics():
from copy import deepcopy
import pickle
obj = ChemicalMetadata(pubchemid=712, CAS=50000, formula='CH2O', MW=30.02598, smiles='C=O', InChI='CH2O/c1-2/h1H2',
InChI_key='WSFSSNUMVMOOMR-UHFFFAOYSA-N', iupac_name='methanal', common_name='formaldehyde',
synonyms=['methanal', 'formaldehyde', 'formalin', 'methanal', 'methylene oxide'])
assert eval(obj.__repr__()) == obj
assert hash(eval(obj.__repr__())) == hash(obj)

# Test equality with identical object
assert obj == obj

# Test hash consistency
assert hash(obj) == hash(obj)

# Test deepcopy
obj_copy = deepcopy(obj)
assert obj == obj_copy
assert hash(obj) == hash(obj_copy)

# Test pickling
obj_pickle = pickle.loads(pickle.dumps(obj))
assert obj_pickle == obj
assert hash(obj_pickle) == hash(obj)

# Test hash consistency after accessing computed property
hash_before = hash(obj)
_ = obj.charge
hash_after = hash(obj)
assert hash_before == hash_after


def test_ChemicalMetadata_inequality():
base_obj = ChemicalMetadata(
pubchemid=712,
CAS=50000,
formula='CH2O',
MW=30.02598,
smiles='C=O',
InChI='CH2O/c1-2/h1H2',
InChI_key='WSFSSNUMVMOOMR-UHFFFAOYSA-N',
iupac_name='methanal',
common_name='formaldehyde',
synonyms=['methanal', 'formaldehyde']
)

# Test inequality with modified attributes
modifications = {
'pubchemid': 713,
'CAS': 50001,
'formula': 'CH3O',
'MW': 30.02599,
'smiles': 'CO',
'InChI': 'different_inchi',
'InChI_key': 'different_key',
'iupac_name': 'different_name',
'common_name': 'different_common_name',
'synonyms': ['different', 'synonyms']
}

for attr, new_value in modifications.items():
kwargs = {k: getattr(base_obj, k) for k in base_obj.__slots__ if k != '_charge'}
kwargs[attr] = new_value
different_obj = ChemicalMetadata(**kwargs)
assert base_obj != different_obj
assert hash(base_obj) != hash(different_obj)

def test_formula_search_exceptions():
"""
Test that FORMULA_SEARCH_BEFORE_SMILES_EXCEPTIONS contains exactly the
Expand Down

0 comments on commit f239172

Please sign in to comment.