diff --git a/cirpy.py b/cirpy.py index d417485..cd94287 100644 --- a/cirpy.py +++ b/cirpy.py @@ -6,9 +6,9 @@ https://github.com/mcs07/CIRpy """ -from __future__ import print_function -from __future__ import unicode_literals -from __future__ import division + + + import functools import inspect import logging @@ -19,8 +19,10 @@ from urllib.parse import quote, urlencode from urllib.request import urlopen except ImportError: - from urllib import urlencode - from urllib2 import quote, urlopen, HTTPError + from urllib.parse import urlencode + from urllib.parse import quote + from urllib.request import urlopen + from urllib.error import HTTPError try: from lxml import etree diff --git a/cirpy.py.bak b/cirpy.py.bak new file mode 100644 index 0000000..d417485 --- /dev/null +++ b/cirpy.py.bak @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +""" +CIRpy + +Python interface for the Chemical Identifier Resolver (CIR) by the CADD Group at the NCI/NIH. +https://github.com/mcs07/CIRpy +""" + +from __future__ import print_function +from __future__ import unicode_literals +from __future__ import division +import functools +import inspect +import logging +import os + +try: + from urllib.error import HTTPError + from urllib.parse import quote, urlencode + from urllib.request import urlopen +except ImportError: + from urllib import urlencode + from urllib2 import quote, urlopen, HTTPError + +try: + from lxml import etree +except ImportError: + try: + import xml.etree.cElementTree as etree + except ImportError: + import xml.etree.ElementTree as etree + + +__author__ = 'Matt Swain' +__email__ = 'm.swain@me.com' +__version__ = '1.0.2' +__license__ = 'MIT' + +log = logging.getLogger('cirpy') +log.addHandler(logging.NullHandler()) + +API_BASE = 'https://cactus.nci.nih.gov/chemical/structure' +FILE_FORMATS = { + 'alc', 'cdxml', 'cerius', 'charmm', 'cif', 'cml', 'ctx', 'gjf', 'gromacs', 'hyperchem', 'jme', 'maestro', 'mol', + 'mol2', 'mrv', 'pdb', 'sdf3000', 'sln', 'xyz' +} + + +def construct_api_url(input, representation, resolvers=None, get3d=False, tautomers=False, xml=True, **kwargs): + """Return the URL for the desired API endpoint. + + :param string input: Chemical identifier to resolve + :param string representation: Desired output representation + :param list(str) resolvers: (Optional) Ordered list of resolvers to use + :param bool get3d: (Optional) Whether to return 3D coordinates (where applicable) + :param bool tautomers: (Optional) Whether to return all tautomers + :param bool xml: (Optional) Whether to return full XML response + :returns: CIR API URL + :rtype: str + """ + # File formats require representation=file and the format in the querystring + if representation in FILE_FORMATS: + kwargs['format'] = representation + representation = 'file' + # Prepend input with 'tautomers:' to return all tautomers + if tautomers: + input = 'tautomers:%s' % input + url = '%s/%s/%s' % (API_BASE, quote(input), representation) + if xml: + url += '/xml' + if resolvers: + kwargs['resolver'] = ','.join(resolvers) + if get3d: + kwargs['get3d'] = True + if kwargs: + url += '?%s' % urlencode(kwargs) + return url + + +def request(input, representation, resolvers=None, get3d=False, tautomers=False, **kwargs): + """Make a request to CIR and return the XML response. + + :param string input: Chemical identifier to resolve + :param string representation: Desired output representation + :param list(string) resolvers: (Optional) Ordered list of resolvers to use + :param bool get3d: (Optional) Whether to return 3D coordinates (where applicable) + :param bool tautomers: (Optional) Whether to return all tautomers + :returns: XML response from CIR + :rtype: Element + :raises HTTPError: if CIR returns an error code + :raises ParseError: if CIR response is uninterpretable + """ + url = construct_api_url(input, representation, resolvers, get3d, tautomers, **kwargs) + log.debug('Making request: %s', url) + response = urlopen(url) + return etree.parse(response).getroot() + + +class Result(object): + """A single result returned by CIR.""" + + def __init__(self, input, notation, input_format, resolver, representation, value): + """ + + :param string input: Originally supplied input identifier that produced this result + :param string notation: Identifier matched by the resolver or tautomer ID + :param string input_format: Format of the input as interpreted by the resolver + :param string resolver: Resolver used to produce this result + :param string representation: Requested output representation + :param value: Actual result value + :type value: string or list(string) + """ + self.input = input + self.representation = representation + self.resolver = resolver + self.input_format = input_format + self.notation = notation + self.value = value + + def __repr__(self): + return 'Result(input=%r, representation=%r, resolver=%r, input_format=%r, notation=%r, value=%r)' \ + % (self.input, self.representation, self.resolver, self.input_format, self.notation, self.value) + + def __str__(self): + return self.value + + def __eq__(self, other): + return isinstance(other, type(self)) and self.__dict__ == other.__dict__ + + def __getitem__(self, prop): + """Allow dict-style access to attributes to ease transition from when results were dicts.""" + if prop in self.__dict__: + return getattr(self, prop) + raise KeyError(prop) + + def __setitem__(self, prop, val): + """Allow dict-style setting of attributes to ease transition from when results were dicts.""" + setattr(self, prop, val) + + def __contains__(self, prop): + """Allow dict-style checking of attributes to ease transition from when results were dicts.""" + return prop in self.__dict__ + + def to_dict(self): + """Return a dictionary containing Result data.""" + return self.__dict__ + + +def query(input, representation, resolvers=None, get3d=False, tautomers=False, **kwargs): + """Get all results for resolving input to the specified output representation. + + :param string input: Chemical identifier to resolve + :param string representation: Desired output representation + :param list(string) resolvers: (Optional) Ordered list of resolvers to use + :param bool get3d: (Optional) Whether to return 3D coordinates (where applicable) + :param bool tautomers: (Optional) Whether to return all tautomers + :returns: List of resolved results + :rtype: list(Result) + :raises HTTPError: if CIR returns an error code + :raises ParseError: if CIR response is uninterpretable + """ + tree = request(input, representation, resolvers, get3d, tautomers, **kwargs) + results = [] + for data in tree.findall('.//data'): + value = [item.text for item in data.findall('item')] + result = Result( + input=tree.attrib['string'], + representation=tree.attrib['representation'], + resolver=data.attrib['resolver'], + input_format=data.attrib['string_class'], + notation=data.attrib['notation'], + value=value[0] if len(value) == 1 else value + ) + results.append(result) + log.debug('Received %s query results', len(results)) + return results + + +def resolve(input, representation, resolvers=None, get3d=False, **kwargs): + """Resolve input to the specified output representation. + + :param string input: Chemical identifier to resolve + :param string representation: Desired output representation + :param list(string) resolvers: (Optional) Ordered list of resolvers to use + :param bool get3d: (Optional) Whether to return 3D coordinates (where applicable) + :returns: Output representation or None + :rtype: string or None + :raises HTTPError: if CIR returns an error code + :raises ParseError: if CIR response is uninterpretable + """ + # Take first result from XML query + results = query(input, representation, resolvers, False, get3d, **kwargs) + result = results[0].value if results else None + return result + + +def resolve_image(input, resolvers=None, fmt='png', width=300, height=300, frame=False, crop=None, bgcolor=None, + atomcolor=None, hcolor=None, bondcolor=None, framecolor=None, symbolfontsize=11, linewidth=2, + hsymbol='special', csymbol='special', stereolabels=False, stereowedges=True, header=None, footer=None, + **kwargs): + """Resolve input to a 2D image depiction. + + :param string input: Chemical identifier to resolve + :param list(string) resolvers: (Optional) Ordered list of resolvers to use + :param string fmt: (Optional) gif or png image format (default png) + + :param int width: (Optional) Image width in pixels (default 300) + :param int height: (Optional) Image height in pixels (default 300) + :param bool frame: (Optional) Whether to show border frame (default False) + :param int crop: (Optional) Crop image with specified padding + + :param int symbolfontsize: (Optional) Atom label font size (default 11) + :param int linewidth: (Optional) Bond line width (default 2) + + :param string bgcolor: (Optional) Background color + :param string atomcolor: (Optional) Atom label color + :param string hcolor: (Optional) Hydrogen atom label color + :param string bondcolor: (Optional) Bond color + :param string framecolor: (Optional) Border frame color + + :param bool hsymbol: (Optional) Hydrogens: all, special or none (default special) + :param bool csymbol: (Optional) Carbons: all, special or none (default special) + :param bool stereolabels: (Optional) Whether to show stereochemistry labels (default False) + :param bool stereowedges: (Optional) Whether to show wedge/dash bonds (default True) + :param string header: (Optional) Header text above structure + :param string footer: (Optional) Footer text below structure + + """ + # Aggregate all arguments into kwargs + args, _, _, values = inspect.getargvalues(inspect.currentframe()) + for arg in args: + if values[arg] is not None: + kwargs[arg] = values[arg] + # Turn off anti-aliasing for transparent background + if kwargs.get('bgcolor') == 'transparent': + kwargs['antialiasing'] = False + # Renamed parameters + if 'stereolabels' in kwargs: + kwargs['showstereo'] = kwargs.pop('stereolabels') + if 'fmt' in kwargs: + kwargs['format'] = kwargs.pop('fmt') + # Toggle stereo wedges + if 'stereowedges' in kwargs: + status = kwargs.pop('stereowedges') + kwargs.update({'wedges': status, 'dashes': status}) + # Constant values + kwargs.update({'representation': 'image', 'xml': False}) + url = construct_api_url(**kwargs) + log.debug('Making image request: %s', url) + response = urlopen(url) + return response.read() + + +# TODO: Support twirl as fmt paramter? +# TODO: ipython html repr twirl, ipython png repr image + + + +def download(input, filename, representation, overwrite=False, resolvers=None, get3d=False, **kwargs): + """Convenience function to save a CIR response as a file. + + This is just a simple wrapper around the resolve function. + + :param string input: Chemical identifier to resolve + :param string filename: File path to save to + :param string representation: Desired output representation + :param bool overwrite: (Optional) Whether to allow overwriting of an existing file + :param list(string) resolvers: (Optional) Ordered list of resolvers to use + :param bool get3d: (Optional) Whether to return 3D coordinates (where applicable) + :raises HTTPError: if CIR returns an error code + :raises ParseError: if CIR response is uninterpretable + :raises IOError: if overwrite is False and file already exists + """ + result = resolve(input, representation, resolvers, get3d, **kwargs) + # Just log and return if nothing resolved + if not result: + log.debug('No file to download.') + return + # Only overwrite an existing file if explicitly instructed to. + if not overwrite and os.path.isfile(filename): + raise IOError("%s already exists. Use 'overwrite=True' to overwrite it." % filename) + # Ensure file ends with a newline + if not result.endswith('\n'): + result += '\n' + with open(filename, 'w') as f: + f.write(result) + + +def memoized_property(fget): + """Decorator to create memoized properties.""" + attr_name = '_{0}'.format(fget.__name__) + + @functools.wraps(fget) + def fget_memoized(self): + if not hasattr(self, attr_name): + setattr(self, attr_name, fget(self)) + return getattr(self, attr_name) + return property(fget_memoized) + + +class Molecule(object): + """Class to hold and cache the structure information for a given CIR input.""" + + def __init__(self, input, resolvers=None, get3d=False, **kwargs): + """Initialize with a resolver input.""" + self.input = input + self.resolvers = resolvers + self.get3d = get3d + self.kwargs = kwargs + log.debug('Instantiated Molecule: %s' % self) + + def __repr__(self): + return 'Molecule(input=%r, resolvers=%r, get3d=%r, kwargs=%r)' \ + % (self.input, self.resolvers, self.get3d, self.kwargs) + + @memoized_property + def stdinchi(self): + """Standard InChI.""" + return resolve(self.input, 'stdinchi', self.resolvers, **self.kwargs) + + @memoized_property + def stdinchikey(self): + """Standard InChIKey.""" + return resolve(self.input, 'stdinchikey', self.resolvers, **self.kwargs) + + @memoized_property + def inchi(self): + """Non-standard InChI. (Uses options DONOTADDH W0 FIXEDH RECMET NEWPS SPXYZ SAsXYZ Fb Fnud).""" + return resolve(self.input, 'inchi', self.resolvers, **self.kwargs) + + @memoized_property + def smiles(self): + """SMILES string.""" + return resolve(self.input, 'smiles', self.resolvers, **self.kwargs) + + @memoized_property + def ficts(self): + """FICTS NCI/CADD hashed structure identifier.""" + return resolve(self.input, 'ficts', self.resolvers, **self.kwargs) + + @memoized_property + def ficus(self): + """FICuS NCI/CADD hashed structure identifier.""" + return resolve(self.input, 'ficus', self.resolvers, **self.kwargs) + + @memoized_property + def uuuuu(self): + """uuuuu NCI/CADD hashed structure identifier.""" + return resolve(self.input, 'uuuuu', self.resolvers, **self.kwargs) + + @memoized_property + def hashisy(self): + """CACTVS HASHISY identifier.""" + return resolve(self.input, 'hashisy', self.resolvers, **self.kwargs) + + @memoized_property + def sdf(self): + """SDF file.""" + return resolve(self.input, 'sdf', self.resolvers, **self.kwargs) + + @memoized_property + def names(self): + """List of chemical names.""" + return resolve(self.input, 'names', self.resolvers, **self.kwargs) + + @memoized_property + def iupac_name(self): + """IUPAC approved name.""" + return resolve(self.input, 'iupac_name', self.resolvers, **self.kwargs) + + @memoized_property + def cas(self): + """CAS registry numbers.""" + return resolve(self.input, 'cas', self.resolvers, **self.kwargs) + + @memoized_property + def mw(self): + """Molecular weight.""" + return resolve(self.input, 'mw', self.resolvers, **self.kwargs) + + @memoized_property + def formula(self): + """Molecular formula""" + return resolve(self.input, 'formula', self.resolvers, **self.kwargs) + + @memoized_property + def h_bond_donor_count(self): + """Hydrogen bond donor count.""" + return resolve(self.input, 'h_bond_donor_count', self.resolvers, **self.kwargs) + + @memoized_property + def h_bond_acceptor_count(self): + """Hydrogen bond acceptor count.""" + return resolve(self.input, 'h_bond_acceptor_count', self.resolvers, **self.kwargs) + + @memoized_property + def h_bond_center_count(self): + """Hydrogen bond center count.""" + return resolve(self.input, 'h_bond_center_count', self.resolvers, **self.kwargs) + + @memoized_property + def rule_of_5_violation_count(self): + """Rule of 5 violation count.""" + return resolve(self.input, 'rule_of_5_violation_count', self.resolvers, **self.kwargs) + + @memoized_property + def rotor_count(self): + """Rotor count.""" + return resolve(self.input, 'rotor_count', self.resolvers, **self.kwargs) + + @memoized_property + def effective_rotor_count(self): + """Effective rotor count.""" + return resolve(self.input, 'effective_rotor_count', self.resolvers, **self.kwargs) + + @memoized_property + def ring_count(self): + """Ring count.""" + return resolve(self.input, 'ring_count', self.resolvers, **self.kwargs) + + @memoized_property + def ringsys_count(self): + """Ring system count.""" + return resolve(self.input, 'ringsys_count', self.resolvers, **self.kwargs) + + @memoized_property + def image(self): + """2D image depiction.""" + return resolve_image(self.input, self.resolvers, **self.kwargs) + + @property + def image_url(self): + """URL of a GIF image.""" + return construct_api_url(self.input, 'image', self.resolvers, False, self.get3d, False, **self.kwargs) + + @property + def twirl_url(self): + """Url of a TwirlyMol 3D viewer.""" + return construct_api_url(self.input, 'twirl', self.resolvers, False, self.get3d, False, **self.kwargs) + + def download(self, filename, representation, overwrite=False): + """Download the resolved structure as a file. + + :param string filename: File path to save to + :param string representation: Desired output representation + :param bool overwrite: (Optional) Whether to allow overwriting of an existing file + """ + download(self.input, filename, representation, overwrite, self.resolvers, self.get3d, **self.kwargs) diff --git a/cirpy_test.py b/cirpy_test.py index eb6b18c..6e14735 100644 --- a/cirpy_test.py +++ b/cirpy_test.py @@ -6,9 +6,9 @@ https://github.com/mcs07/CIRpy """ -from __future__ import print_function -from __future__ import unicode_literals -from __future__ import division + + + import logging import os import time @@ -17,7 +17,7 @@ try: from urllib.error import HTTPError except ImportError: - from urllib2 import HTTPError + from urllib.error import HTTPError try: from lxml import etree diff --git a/cirpy_test.py.bak b/cirpy_test.py.bak new file mode 100644 index 0000000..eb6b18c --- /dev/null +++ b/cirpy_test.py.bak @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- +""" +Unit tests for cirpy.py + +Python interface for the Chemical Identifier Resolver (CIR) by the CADD Group at the NCI/NIH. +https://github.com/mcs07/CIRpy +""" + +from __future__ import print_function +from __future__ import unicode_literals +from __future__ import division +import logging +import os +import time +import unittest + +try: + from urllib.error import HTTPError +except ImportError: + from urllib2 import HTTPError + +try: + from lxml import etree +except ImportError: + try: + import xml.etree.cElementTree as etree + except ImportError: + import xml.etree.ElementTree as etree + +from cirpy import request, resolve, query, Molecule, Result, resolve_image + + +logging.basicConfig(level=logging.DEBUG) + + +class RateLimitTestCase(unittest.TestCase): + """TestCase that delays before each test according to CIRPY_TEST_DELAY environment variable.""" + + def setUp(self): + time.sleep(float(os.environ.get('CIRPY_TEST_DELAY', 0))) + + +class TestRequest(RateLimitTestCase): + """Test basic requests to CIR servers return the expected XML response.""" + + def test_requests(self): + """Test a variety of basic requests to ensure they return the expected XML response.""" + self.assertEqual(request('c1ccccc1', 'names').tag, 'request') + self.assertEqual(request('Aspirin', 'smiles').tag, 'request') + self.assertEqual(len(request('64-17-5', 'stdinchi')), 1) + + def test_no_result_request(self): + """Test that an empty XML response is returned when there are no results.""" + response = request('arguergbaiurg', 'smiles') + self.assertEqual(response.tag, 'request') + self.assertEqual(len(response), 0) + + def test_invalid_representation_request(self): + """Test that HTTPError is raised when an invalid representation is specified.""" + with self.assertRaises(HTTPError): + request('Morphine', 'ogiuewrgpw') + + +class TestQuery(RateLimitTestCase): + """Test the query function returns expected results.""" + + def test_morphine_inchi(self): + """Test morphine query for inchi returns expected result.""" + results = query('morphine', 'inchi') + self.assertEqual(len(results), 2) + self.assertEqual(results[1].input, 'morphine') + self.assertEqual(results[1].representation, 'inchi') + self.assertEqual(results[1].resolver, 'name_by_cir') + self.assertEqual(results[1].input_format, 'chemical name (CIR)') + self.assertEqual(results[1].notation, 'Morphine') + self.assertEqual(results[1].value, 'InChI=1/C17H19NO3/c1-18-7-6-17-10-3-5-13(20)16(17)21-15-12(19)4-2-9(14(15)17)8-11(10)18/h2-5,10-11,13,16,19-20H,6-8H2,1H3/t10-,11+,13?,16-,17-/m0/s1') + + def test_query_dict(self): + """Test dict-style access to result attributes.""" + results = query('Morphine', 'inchi') + self.assertEqual(len(results), 2) + self.assertEqual(results[1]['value'], 'InChI=1/C17H19NO3/c1-18-7-6-17-10-3-5-13(20)16(17)21-15-12(19)4-2-9(14(15)17)8-11(10)18/h2-5,10-11,13,16,19-20H,6-8H2,1H3/t10-,11+,13?,16-,17-/m0/s1') + self.assertEqual(results[1]['notation'], 'Morphine') + self.assertEqual(results[1]['resolver'], 'name_by_cir') + + def test_no_result_query(self): + """Test that an empty list is returned when there are no results.""" + self.assertEqual(query('sjkvhaldfu', 'smiles'), []) + + def test_invalid_representation_query(self): + """Test that HTTPError is raised when an invalid representation is specified.""" + with self.assertRaises(HTTPError): + query('Morphine', 'ogiuewrgpw') + + def test_custom_resolvers(self): + """Test expected results are returned when using custom name resolvers.""" + results = query('2,4,6-trinitrotoluene', 'smiles') + self.assertEqual(len(results), 2) + self.assertEqual(results[0], Result(input='2,4,6-trinitrotoluene', representation='smiles', resolver='name_by_opsin', input_format='IUPAC name (OPSIN)', notation='2,4,6-trinitrotoluene', value='Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O')) + self.assertEqual(results[1], Result(input='2,4,6-trinitrotoluene', representation='smiles', resolver='name_by_cir', input_format='chemical name (CIR)', notation='2,4,6-Trinitrotoluene', value='Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O')) + + def test_result_equality(self): + """Test that identical result objects are considered equal.""" + r1 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'value') + r2 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'value') + r3 = Result('input', 'notation', 'input_format', 'resolver', 'representation', 'another_value') + self.assertEqual(r1, r2) + self.assertNotEqual(r1, r3) + + +class TestResolve(RateLimitTestCase): + """Test the resolve function.""" + + def test_alanine_smiles(self): + """Test that alanine smiles resolves the expected result.""" + self.assertEqual(resolve('Alanine', 'smiles'), 'C[C@H](N)C(O)=O') + + def test_no_results_resolve(self): + """Test that None is returned when there are no results.""" + self.assertEqual(resolve('aruighaelirugaerg', 'inchi'), None) + + def test_invalid_representation_resolve(self): + """Test that HTTPError is raised when an invalid representation is specified.""" + with self.assertRaises(HTTPError): + resolve('Morphine', 'ogiuewrgpw') + + def test_tnt_smiles(self): + """Test that TNT smiles resolves the expected result.""" + self.assertEqual( + resolve('2,4,6-trinitrotoluene', 'smiles'), + 'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O' + ) + + def test_tnt_smiles_custom_resolvers(self): + """Test custom resolvers return the expected result.""" + self.assertEqual( + resolve('2,4,6-trinitrotoluene', 'smiles', ['name_by_opsin', 'name_by_cir']), + 'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O' + ) + self.assertEqual( + resolve('2,4,6-trinitrotoluene', 'smiles', ['name_by_cir', 'name_by_opsin']), + 'Cc1c(cc(cc1[N+]([O-])=O)[N+]([O-])=O)[N+]([O-])=O' + ) + + +class TestMolecule(RateLimitTestCase): + """Test the Molecule class.""" + + def test_molecule_image(self): + """Test Molecule image_url attribute.""" + self.assertEqual( + Molecule('C#N', ['smiles']).image_url, + 'https://cactus.nci.nih.gov/chemical/structure/C%23N/image?resolver=smiles' + ) + + +class TestFiles(RateLimitTestCase): + """Test resolving to file formats.""" + + def test_cml(self): + """Test CML file format is resolved.""" + cmlstring = resolve('Aspirin', 'cml') + cml = etree.fromstring(cmlstring) + self.assertEqual(cml.tag, '{http://www.xml-cml.org/schema/cml2/core}list') + self.assertEqual(len(cml.findall('.//{http://www.xml-cml.org/schema/cml2/core}molecule')), 1) + + def test_pdb(self): + """Test PDB file format is resolved.""" + result = resolve('Aspirin', 'pdb') + self.assertIn('HEADER', result) + self.assertIn('ATOM', result) + self.assertIn('CONECT', result) + + +class TestImage(RateLimitTestCase): + """Test resolving to image depiction.""" + + def test_png_format(self): + """Test that response looks like valid PNG data.""" + img = resolve_image('Glucose') + self.assertEqual(img[:8], b'\x89PNG\x0d\x0a\x1a\x0a') + + def test_gif_format(self): + """Test that response looks like valid GIF data.""" + img = resolve_image('Glucose', fmt='gif') + self.assertEqual(img[:4], b'GIF8') + + +if __name__ == '__main__': + unittest.main() diff --git a/docs/source/conf.py b/docs/source/conf.py index 45ab904..11f66a6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -39,8 +39,8 @@ master_doc = 'index' # General information about the project. -project = u'CIRpy' -copyright = u'2015, Matt Swain' +project = 'CIRpy' +copyright = '2015, Matt Swain' # The version info for the project you're documenting, acts as replacement for |version| and |release|, also used in # various other places throughout the built documents. @@ -179,7 +179,7 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto, manual, or own class]). latex_documents = [ - ('index', 'CIRpy.tex', u'CIRpy Documentation', u'Matt Swain', 'manual'), + ('index', 'CIRpy.tex', 'CIRpy Documentation', 'Matt Swain', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of the title page. @@ -205,7 +205,7 @@ # One entry per manual page. List of tuples (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'cirpy', u'CIRpy Documentation', [u'Matt Swain'], 1) + ('index', 'cirpy', 'CIRpy Documentation', ['Matt Swain'], 1) ] # If true, show URL addresses after external links. @@ -217,7 +217,7 @@ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, dir menu entry, description, category) texinfo_documents = [ - ('index', 'CIRpy', u'CIRpy Documentation', u'Matt Swain', 'CIRpy', + ('index', 'CIRpy', 'CIRpy Documentation', 'Matt Swain', 'CIRpy', 'One line description of project.', 'Miscellaneous'), ] @@ -237,10 +237,10 @@ # -- Options for Epub output ---------------------------------------------- # Bibliographic Dublin Core info. -epub_title = u'CIRpy' -epub_author = u'Matt Swain' -epub_publisher = u'Matt Swain' -epub_copyright = u'2015, Matt Swain' +epub_title = 'CIRpy' +epub_author = 'Matt Swain' +epub_publisher = 'Matt Swain' +epub_copyright = '2015, Matt Swain' # The basename for the epub file. It defaults to the project name. #epub_basename = u'CIRpy' diff --git a/docs/source/conf.py.bak b/docs/source/conf.py.bak new file mode 100644 index 0000000..45ab904 --- /dev/null +++ b/docs/source/conf.py.bak @@ -0,0 +1,312 @@ +# -*- coding: utf-8 -*- +# CIRpy documentation build configuration file, created by sphinx-quickstart on Tue Mar 24 16:12:38 2015. +# This file is execfile()d with the current directory set to its containing dir. +# Note that not all possible configuration values are present in this autogenerated file. +# All configuration values have a default; values that are commented out serve to show the default. + +import sys +import os + +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +# If extensions (or modules to document with autodoc) are in another directory, add these directories to sys.path here. +# If the directory is relative to the documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('../..')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions coming with Sphinx +# (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'CIRpy' +copyright = u'2015, Matt Swain' + +# The version info for the project you're documenting, acts as replacement for |version| and |release|, also used in +# various other places throughout the built documents. +# +# The short X.Y version. +version = '1.0.2' +# The full version, including alpha/beta/rc tags. +release = '1.0.2' + +# The language for content autogenerated by Sphinx. Refer to documentation for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and directories to ignore when looking for source +# files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for a list of builtin themes. +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +#html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme further. For a list of options available +# for each theme, see the documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the docs. This file should be a Windows icon +# file (.ico) being 16x16 or 32x32 pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, relative to this directory. They are +# copied after the builtin static files, so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or .htaccess) here, relative to this directory. +# These files are copied directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will contain a tag referring to it. The +# value of this option must be the base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'CIRpydoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'a4paper', + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '12pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'CIRpy.tex', u'CIRpy Documentation', u'Matt Swain', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, not chapters. +latex_use_parts = False + +# If true, show page references after internal links. +latex_show_pagerefs = True + +# If true, show URL addresses after external links. +latex_show_urls = True + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +latex_domain_indices = False + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'cirpy', u'CIRpy Documentation', [u'Matt Swain'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, dir menu entry, description, category) +texinfo_documents = [ + ('index', 'CIRpy', u'CIRpy Documentation', u'Matt Swain', 'CIRpy', + 'One line description of project.', 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + + +# -- Options for Epub output ---------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = u'CIRpy' +epub_author = u'Matt Swain' +epub_publisher = u'Matt Swain' +epub_copyright = u'2015, Matt Swain' + +# The basename for the epub file. It defaults to the project name. +#epub_basename = u'CIRpy' + +# The HTML theme for the epub output. Since the default themes are not optimized for small screen space, using the same +# theme for HTML and epub output is usually not wise. This defaults to 'epub', a theme designed to save visual space. +#epub_theme = 'epub' + +# The language of the text. It defaults to the language option +# or en if the language is not set. +#epub_language = '' + +# The scheme of the identifier. Typical schemes are ISBN or URL. +#epub_scheme = '' + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +#epub_identifier = '' + +# A unique identification for the text. +#epub_uid = '' + +# A tuple containing the cover image and cover page html template filenames. +#epub_cover = () + +# A sequence of (type, uri, title) tuples for the guide element of content.opf. +#epub_guide = () + +# HTML files that should be inserted before the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_pre_files = [] + +# HTML files shat should be inserted after the pages created by sphinx. +# The format is a list of tuples containing the path and title. +#epub_post_files = [] + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# The depth of the table of contents in toc.ncx. +#epub_tocdepth = 3 + +# Allow duplicate toc entries. +#epub_tocdup = True + +# Choose between 'default' and 'includehidden'. +#epub_tocscope = 'default' + +# Fix unsupported image types using the PIL. +#epub_fix_images = False + +# Scale large images. +#epub_max_image_width = 0 + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#epub_show_urls = 'inline' + +# If false, no index is generated. +#epub_use_index = True + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('http://docs.python.org/', None)} + +# Sort autodoc members by the order they appear in the source code +autodoc_member_order = 'bysource' + +# Concatenate the class and __init__ docstrings together +autoclass_content = 'both'