# -*- coding: utf-8 -*-
"""
chemspipy.objects
~~~~~~~~~~~~~~~~~
Objects returned by ChemSpiPy API methods.
:copyright: Copyright 2014 by Matt Swain.
:license: MIT, see LICENSE file for more details.
"""
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
from .utils import memoized_property, timestamp
[docs]class Compound(object):
""" A class for retrieving and caching details about a specific ChemSpider record.
The purpose of this class is to provide access to various parts of the ChemSpider API that return information about
a compound given its ChemSpider ID. Information is loaded lazily when requested, and cached for future access.
"""
def __init__(self, cs, csid):
"""
:param ChemSpider cs: ``ChemSpider`` session.
:param int|string csid: ChemSpider ID.
"""
self._cs = cs
self._csid = int(csid)
# TODO: Allow optional initialize with a record-type response from the API (kwarg or class method from_dict?).
def __eq__(self, other):
return isinstance(other, Compound) and self.csid == other.csid
def __repr__(self):
return 'Compound(%r)' % self.csid
def _repr_png_(self):
"""For IPython notebook, display 2D image."""
return self.image
@property
def csid(self):
"""ChemSpider ID."""
return self._csid
# TODO: csid setter that clears cached properties?
@property
def image_url(self):
"""Return the URL of a PNG image of the 2D chemical structure."""
return 'http://www.chemspider.com/ImagesHandler.ashx?id=%s' % self.csid
@memoized_property
def _compound_info(self):
"""Request compound info and cache the result."""
return self._cs.get_compound_info(self.csid)
@memoized_property
def _extended_compound_info(self):
"""Request extended compound info and cache the result."""
return self._cs.get_extended_compound_info(self.csid)
@property
def molecular_formula(self):
"""Return the molecular formula for this Compound.
:rtype: string
"""
return self._extended_compound_info['molecular_formula']
@property
def smiles(self):
"""Return the SMILES for this Compound.
:rtype: string
"""
return self._compound_info['smiles']
@property
def stdinchi(self):
"""Return the Standard InChI for this Compound.
:rtype: string
"""
return self._compound_info['inchi']
@property
def stdinchikey(self):
"""Return the Standard InChIKey for this Compound.
:rtype: string
"""
return self._compound_info['inchikey']
@property
def inchi(self):
"""Return the InChI for this Compound.
:rtype: string
"""
return self._extended_compound_info['inchi']
@property
def inchikey(self):
"""Return the InChIKey for this Compound.
:rtype: string
"""
return self._extended_compound_info['inchikey']
@property
def average_mass(self):
"""Return the average mass of this Compound.
:rtype: float
"""
return self._extended_compound_info['average_mass']
@property
def molecular_weight(self):
"""Return the molecular weight of this Compound.
:rtype: float
"""
return self._extended_compound_info['molecular_weight']
@property
def monoisotopic_mass(self):
"""Return the monoisotopic mass of this Compound.
:rtype: float
"""
return self._extended_compound_info['monoisotopic_mass']
@property
def nominal_mass(self):
"""Return the nominal mass of this Compound.
:rtype: float
"""
return self._extended_compound_info['nominal_mass']
@property
def alogp(self):
"""Return the calculated AlogP for this Compound.
:rtype: float
"""
return self._extended_compound_info['alogp']
@property
def xlogp(self):
"""Return the calculated XlogP for this Compound.
:rtype: float
"""
return self._extended_compound_info['xlogp']
@property
def common_name(self):
"""Return the common name for this Compound.
:rtype: string
"""
return self._extended_compound_info['common_name']
@memoized_property
def mol_2d(self):
"""Return the MOL file for this Compound with 2D coordinates.
:rtype: string
"""
return self._cs.get_record_mol(self.csid, calc3d=False)
@memoized_property
def mol_3d(self):
"""Return the MOL file for this Compound with 3D coordinates.
:rtype: string
"""
return self._cs.get_record_mol(self.csid, calc3d=True)
@memoized_property
def mol_raw(self):
"""Return unprocessed MOL file for this Compound.
:rtype: string
"""
return self._cs.get_original_mol(self.csid)
@memoized_property
def image(self):
"""Return a 2D depiction of this Compound.
:rtype: bytes
"""
return self._cs.get_compound_thumbnail(self.csid)
@memoized_property
def spectra(self):
"""Return all the available spectral data for this Compound.
:rtype: list[:class:`~chemspipy.Spectrum`]
"""
return [Spectrum.from_info_dict(self._cs, info) for info in self._cs.get_spectra_info_list([self.csid])]
[docs]class Spectrum(object):
""" A class for retrieving and caching details about a Spectrum."""
def __init__(self, cs, spectrum_id):
"""Initializing a Spectrum from a spectrum ID requires a subscriber role security token.
:param ChemSpider cs: ``ChemSpider`` session.
:param int|string spectrum_id: Spectrum ID.
"""
self._cs = cs
self._spectrum_id = int(spectrum_id)
def __eq__(self, other):
return isinstance(other, Spectrum) and self.spectrum_id == other.spectrum_id
def __repr__(self):
return 'Spectrum(%r)' % self.spectrum_id
[docs] @classmethod
def from_info_dict(cls, cs, info):
"""Initialize a Spectrum from an info dict that has already been retrieved."""
s = cls(cs, info['spectrum_id'])
s._info = info
return s
@property
def _spectrum_info(self):
"""Full spectrum info.
:rtype: dict
"""
if not hasattr(self, '_info'):
self._info = self._cs.get_spectrum_info(self._spectrum_id)
return self._info
@property
def spectrum_id(self):
"""Spectrum ID.
:rtype: int
"""
return self._spectrum_id
@property
def csid(self):
"""ChemSpider ID of related compound.
:rtype: int
"""
return self._spectrum_info['csid']
@property
def spectrum_type(self):
"""Spectrum type.
Possible values include HNMR, CNMR, IR, UV-Vis, NIR, EI, 2D1H1HCOSY, 2D1H13CD, APCI+, R, MALDI+, 2D1H13CLR,
APPI-, CI+ve, ESI+, 2D1H1HOESY, FNMR, CI-ve, ESI-, PNMR.
:rtype: string
"""
return self._spectrum_info['spectrum_type']
@property
def file_name(self):
"""Spectrum file name.
:rtype: string
"""
return self._spectrum_info['file_name']
@property
def comments(self):
"""Spectrum comments. Can be None.
:rtype: string
"""
return self._spectrum_info.get('comments')
@property
def url(self):
"""Spectrum URL.
:rtype: string
"""
return 'https://www.chemspider.com/FilesHandler.ashx?type=blob&disp=1&id=%s' % self.spectrum_id
@memoized_property
def data(self):
"""Spectrum data file contents. Requires an additional request. Result is cached.
:rtype: string
"""
r = self._cs.http.get(self.url)
return r.text
@property
def original_url(self):
"""Original spectrum URL. Can be None.
:rtype: string
"""
return self._spectrum_info.get('original_url')
@property
def submitted_date(self):
"""Spectrum submitted date.
:rtype: :py:class:`datetime.datetime`
"""
return timestamp(self._spectrum_info['submitted_date'])