From 71aef3a94c1b8d60171b01342a24a900b7187bd1 Mon Sep 17 00:00:00 2001 From: Thomas Cokelaer Date: Wed, 8 Mar 2023 15:08:54 +0100 Subject: [PATCH] Fix tests and update documentation --- README.rst | 4 + doc/all_relations.png | Bin 0 -> 16314 bytes doc/external_references.rst | 1 - doc/geneprof_tutorial.rst | 226 -------------------------------- doc/pymol_app.py | 33 +++++ doc/references.rst | 6 +- doc/tutorials.rst | 1 - src/bioservices/chembl.py | 14 +- src/bioservices/psicquic.py | 32 ++--- src/bioservices/unichem.py | 4 +- test/webservices/test_chembl.py | 6 +- test/webservices/test_kegg.py | 12 +- test/webservices/test_pride.py | 7 +- 13 files changed, 77 insertions(+), 269 deletions(-) create mode 100644 doc/all_relations.png delete mode 100644 doc/geneprof_tutorial.rst create mode 100644 doc/pymol_app.py diff --git a/README.rst b/README.rst index 9465e01c..c6ad6b5c 100644 --- a/README.rst +++ b/README.rst @@ -20,6 +20,10 @@ BIOSERVICES: access to biological web services programmatically .. image:: https://static.pepy.tech/personalized-badge/bioservices?period=month&units=international_system&left_color=black&right_color=orange&left_text=Downloads :target: https://pepy.tech/project/bioservices +.. image:: https://anaconda.org/conda-forge/bioservices/badges/version.svg + :target: https://anaconda.org/conda-forge/bioservices + + |Codacy-Grade| diff --git a/doc/all_relations.png b/doc/all_relations.png new file mode 100644 index 0000000000000000000000000000000000000000..15a508a5948c3ffcf91a530cfa50965666de7642 GIT binary patch literal 16314 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 literal 0 HcmV?d00001 diff --git a/doc/external_references.rst b/doc/external_references.rst index 88f3e165..fdeb07e4 100644 --- a/doc/external_references.rst +++ b/doc/external_references.rst @@ -5,7 +5,6 @@ References to BioServices on the Web * Galaxy: See the Log Archive at `Galaxy log archive `_ * EBI: See `EBI programming web services `_ * WikiPathways: `references `_ -* GeneProf: `example python `_ * http://www.scoop.it/t/bioinformatique * http://bioinfo-fr.net/bioservices-module-python * http://devbio.eu/?p=resources&presel=bioinfo diff --git a/doc/geneprof_tutorial.rst b/doc/geneprof_tutorial.rst deleted file mode 100644 index 89697f5c..00000000 --- a/doc/geneprof_tutorial.rst +++ /dev/null @@ -1,226 +0,0 @@ -GeneProf tutorial -===================== - -.. topic:: GeneProf tutorial - - .. versionadded:: 1.2.0 - .. sectionauthor:: Thomas Cokelaer, Dec 2013 - -`GeneProf `_ is a web-based, graphical software suite that allows users to analyse data produced using high-throughput sequencing platforms (RNA-seq and ChIP-seq; "Next-Generation Sequencing" or NGS): Next-gen analysis for next-gen data - - -BioServices uses the GeneProf Web Services to enable programmatic access to the public data stored in GeneProf's databases via Python. - -.. note:: GeneProf services is quite versatile and contains many resources and examples. For any technical or scientific questions related to the service itself, please see `GeneProf About&Help `_. - - -Here below you will find a couple of examples related to GeneProf. - - - -Histogram expression data --------------------------------------- -:Reference: https://www.geneprof.org/GeneProf/media/bpsm-2013/ - - -In the example below, we use geneprof to - -#. search for Gene identifiers related to an organism (mouse) and keyword (nanog). -#. From the gene identifiers, retrieve the gene expression values for a given gene in all experiments -#. plot histogram of the log values found above. - - -.. .. plot:: - :include-source: - :width: 80% - -.. note:: broken example on June 2017. Service should be fix soon. Issue - reported to the author. - -:: - - >>> from bioservices import GeneProf - >>> g = GeneProf(verbose=True) - >>> res = g.search_gene_ids("nanog", "mouse") - >>> print(res) - {10090: [29640, 14899]} - >>> expr1 = g.get_expression("mouse", 29640)['values'] - >>> expr2 = g.get_expression("mouse", 14899)['values'] - - >>> import math - >>> values1 = [math.log(x["RPKM"]+1, 2.) for x in expr1] - >>> values2 = [math.log(x["RPKM"]+1, 2.) for x in expr2] - - >>> from pylab import clf, subplot, hist - >>> clf() - >>> subplot(2,1,1) - >>> hist(values1) - >>> subplot(2,1,2) - >>> hist(values2) - - -Transcription factor network of stem cells -------------------------------------------------------- - -:References: https://www.geneprof.org/GeneProf/media/recomb-2013/ - - -Another example, here below consists in retrieving -the binding targets of transcription factors (about 70) in mouse -embryonic stem cells, and generate a SIF network that could be open and visualised in Cytoscape. - -The example below can probably be simplified and make use of tools such as networkx to manipulate -and visualise the final network. Please use with care:: - - >>> # first import and create a GenProf instance - >>> from bioservices import GeneProf - >>> g = GeneProf(verbose=False) - >>> - >>> # find all pubic experimental mouse samples in geneprof - >>> samples = g.get_list_experiment_samples("mouse")['samples'] - >>> # look at entries that contains "Gene" - >>> graph = {} - >>> mapgene = {} - >>> for i, entry in enumerate(samples): - ... print("progress %s/%s" % (i+1, len(samples))) - - ... # keep only entries that have cell type "embryonic stem cell" in the celltype - ... if "Gene" in entry.keys() and "Cell_Type" in entry.keys() and entry["Cell_Type"]=="embryonic stem cell": - ... - ... # aliases - ... sampleId = entry['sample_id'] - ... gene = entry["Gene"] - - ... # get gene id and save mapping in a dictionary to be used later - ... geneId = g.get_gene_id("mouse", "C_NAME", gene)['ids'] - ... mapgene[geneId[0]] = gene - - ... # get targets and print them - ... targets = g.get_targets_by_experiment_sample("mouse", sampleId) - - ... # could be simplied inside the geneprof.py module - ... if 'targets' in targets.keys(): - ... targets = targets['targets'] - - ... # print the results - ... for x in targets: - ... print gene, geneId[0], " ", x['feature_id'] - ... graph[gene] = [x['feature_id'] for x in targets] - - >>> # The graph saved in the graph variables is quite large. Let us simplified keeping target that - >>> # are in the list of genes only - >>> simple_graph = {} - >>> for k, v in graph.iteritems(): - ... simple_graph[k] = [mapgene[x] for x in v if x in mapgene.keys()] - >>> len(simple_graph.keys()) - 72 - >>> sum([len(simple_graph[x]) for x in simple_graph.keys()]) - 2137 - - -Finally, you can look at the graph with your favorite tool such as Cytoscape, Gephi. - -Here below, I'm using a basic graph visualisation tool implemented in `CellNOpt `_, which is not dedicated -for Network visualisation but contains a small interface to graphviz useful in this context (it has a python interface):: - - >>> from cno import CNOGraph - >>> c = CNOGraph() - >>> for k in simple_graph.keys(): - ... for v in simple_graph[k]: - ... c.add_edge(k, v, link="+") - >>> c.centrality_degree() - >>> c.graph['graph'] = {"splines":"true", "size":(20,20), - "dpi":200, "fixedsize":True} - >>> c.graph['node'] = {"width":.01, "height":.01, - 'size':0.01, "fontsize":8} - >>> c.plotdot(prog="fdp", node_attribute="degree") - -.. image:: geneprof_network.png - - - -Integrating expression data in pathways -------------------------------------------------------- - -:References: https://www.geneprof.org/GeneProf/media/recomb-2013/ - - - -This is another example from the reference above but based on tools available in bioservices so as to overlaid highthroughput gene expression -onto pathways and models from KEGG database. - -Fold changes in lymphoma vs. kidney -on selected KEGG pathways - -:: - - >>> from bioservices import KEGG, GeneProf, UniProt - >>> import StringIO - >>> import pandas - >>> g = GeneProf() - >>> k = KEGG() - >>> u = UniProt() - - >>> # load ENCODE RNA-seq into a DataFrame for later - >>> data = g.get_data("11_683_28_1", "txt") - >>> rnaseq = pandas.read_csv(StringIO.StringIO(data), sep="\t") - >>> gene_names = rnaseq['Ensembl Gene ID'] - - >>> # get a pathway diagram for the KEGG path hsa05202 ("Transcriptional - >>> # misregulation in cancers") - >>> res = k.parse(k.get("hsa05202")) - >>> # extract KEGG identifiers corresponding to the genes found in the pathway - >>> keggids = ["hsa:"+x for x in res['GENE'].keys()] - - >>> # we need to map the KEGG Ids to Ensembl Ids. We will use KEGG mapping and uniprot mapping - >>> # for cases where the former does not have associated mapping. - >>> ensemblids = {} - >>> for id_ in keggids: - ... res = k.parse(k.get(id_))['DBLINKS'] - ... if 'Ensembl' in res.keys(): - ... print id_, res['Ensembl'] - ... ensemblids[id_] = res['Ensembl'] - ... else: - ... if "UniProt" in res.keys(): - ... ids = res['UniProt'].split()[0] - ... m = u.mapping("ACC", "ENSEMBL_ID", query=ids) - ... if len(m): ensemblids[id_] = m[ids][0] - ... pass # no links to ensembl DB found - - >>> # what are the KEGG id transformed into Ensembl Ids that are in the ENCODE data set ? - >>> found = [x for x in ensemblids.values() if x in [str(y) for y in gene_names]] - >>> indices = [i for i, x in enumerate(rnaseq['Ensembl Gene ID']) if x in found] - >>> - >>> # now, we can pick out the log2 fold change values for visualization: - >>> data = rnaseq.ix[indices][['Ensembl Gene ID', 'log2FC Lymphoma / EmbryonicKidney']] - >>> # and keep only those that have a negative or positive value - >>> mid = 1.5 - >>> low = data[data['log2FC Lymphoma / EmbryonicKidney']<-mid] - >>> geneid_low = list(low['Ensembl Gene ID']) - >>> up = data[data['log2FC Lymphoma / EmbryonicKidney']>mid] - >>> geneid_up = list(up['Ensembl Gene ID']) - >>> mid = data[abs(data['log2FC Lymphoma / EmbryonicKidney'])>> geneid_mid = list(mid['Ensembl Gene ID']) - - >>> # now that we have the genes (in ensembl format), we need the kegg id - >>> keggid_low = [this for this in keggids if ensemblids[this] in geneid_low] - >>> keggid_mid = [this for this in keggids if ensemblids[this] in geneid_mid] - >>> keggid_up = [this for this in keggids if ensemblids[this] in geneid_up] - >>> # it is now time to look at the expression on the diagram - >>> colors = {} - >>> for id_ in keggids: colors[id_[4:]] = "gray," - >>> for id_ in keggid_low: colors[id_[4:]] = "blue," - >>> for id_ in keggid_up: colors[id_[4:]] = "orange," - >>> for id_ in keggid_mid: colors[id_[4:]] = "yellow," - >>> k.show_pathway("hsa05202", dcolor="white", keggid=colors) - -The last command will popup the KEGG diagram with the expression data on top of the diagram, as shown in the following picture: - -.. image:: geneprof_kegg_expression.png - :width: 100% - - - - - - diff --git a/doc/pymol_app.py b/doc/pymol_app.py new file mode 100644 index 00000000..ab95a222 --- /dev/null +++ b/doc/pymol_app.py @@ -0,0 +1,33 @@ +import __main__ +__main__.pymol_argv = [ 'pymol', '-qc'] # Quiet and no GUI + +import os +if os.path.isfile("bioservices_pdb.png"): + os.remove("bioservices_pdb.png") + +# BioServices 1: obtain the PDB ID from a given uniprot ID (P43403 i.e. ZAP70) +from bioservices import * +print("Retrieving PDB ID") +u = UniProt(verbose=False) +res = u.mapping(fr="UniProtKB_AC-ID", to="PDB", query="P43403") +pdb_id = res['results']['P43403'][0] # e.g, "1FBV" + +# BioServices 2: Download the PDB file from the PDB Web Service +print("Fetching PDB file") +p = pdbe.PDBe() +res = p.get_files(pdb_id) + +# General: save the fetched file in a temporary file +import tempfile +fh = tempfile.NamedTemporaryFile() +fh.write(res) +sname = fh.name + +# THIS IS NOT BIOSERVICES ANYMORE but PYMOL +import pymol +pymol.finish_launching() +pymol.cmd.load(sname) +pymol.cmd.png("bioservices_pdb.png", width="15cm", height="15cm", dpi=140) +#pymol.cmd.png("my_image.png") +# Get out! +pymol.cmd.quit() diff --git a/doc/references.rst b/doc/references.rst index 9a6ad5a9..8c9ede0b 100644 --- a/doc/references.rst +++ b/doc/references.rst @@ -29,7 +29,7 @@ Services ArrayExpress =================== -.. .. automodule:: bioservices.arrayexpress +.. automodule:: bioservices.arrayexpress :members: :undoc-members: :synopsis: @@ -130,10 +130,6 @@ GeneProf Currently removed from the main API from version 1.6.0 onwards. You can still get the code in earlier version or in the github repository in the attic/ directory -.. .. automodule:: bioservices.geneprof - :members: - :undoc-members: - :synopsis: QuickGO ================ diff --git a/doc/tutorials.rst b/doc/tutorials.rst index 4fca6b72..1c5a2d82 100644 --- a/doc/tutorials.rst +++ b/doc/tutorials.rst @@ -21,4 +21,3 @@ welcomed. compound_tutorial.rst convertor_tutorial.rst biomart.rst - geneprof_tutorial.rst diff --git a/src/bioservices/chembl.py b/src/bioservices/chembl.py index 8b2eebe6..89771d03 100644 --- a/src/bioservices/chembl.py +++ b/src/bioservices/chembl.py @@ -694,15 +694,19 @@ def get_organism(self, query=None, limit=20, offset=0, filters=None): params = {"limit": limit, "offset": offset, "filters": filters} return self._get_this_service("organism", query, params=params) + """ + # subservices removed apparatently (march 2023) hence the commented code + def search_protein_class(self, query, limit=20, offset=0): params = {"limit": limit, "offset": offset} return self._search("protein_class", query, params=params) def get_protein_class(self, query=None, limit=20, offset=0, filters=None): - """Protein family classification of TargetComponents""" + "Protein family classification of TargetComponents" params = {"limit": limit, "offset": offset, "filters": filters} return self._get_this_service("protein_class", query, params=params) + """ def get_substructure(self, structure, limit=20, offset=0, filters=None): """Molecule substructure search @@ -906,10 +910,10 @@ def get_image(self, query, dimensions=500, format="png", save=True, view=True, e .. todo:: ignorecoords option """ # NOTE: not async requests here. - self.devtools.check_range(dimensions, 1, 500) - self.devtools.check_param_in_list(engine, ["rdkit", "indigo"]) - self.devtools.check_param_in_list(format, ["png", "svg"]) - queries = self.devtools.to_list(query) + self.services.devtools.check_range(dimensions, 1, 500) + self.services.devtools.check_param_in_list(engine, ["rdkit", "indigo"]) + self.services.devtools.check_param_in_list(format, ["png", "svg"]) + queries = self.services.devtools.to_list(query) res = {"filenames": [], "images": [], "chemblids": []} for query in queries: diff --git a/src/bioservices/psicquic.py b/src/bioservices/psicquic.py index aeddd034..55e572a4 100644 --- a/src/bioservices/psicquic.py +++ b/src/bioservices/psicquic.py @@ -462,7 +462,7 @@ def query( try: index = names.index(service) except ValueError: - self.logging.error("The service you gave (%s) is not registered. See self.registery_names" % service) + self.services.logging.error("The service you gave (%s) is not registered. See self.registery_names" % service) raise ValueError # get the base url according to the service requested @@ -525,7 +525,7 @@ def queryAll( raise ValueError("database %s not in active databases" % x) for name in databases: - self.logging.warning("Querying %s" % name), + self.services.logging.warning("Querying %s" % name), res = self.query( name, query, @@ -541,7 +541,7 @@ def queryAll( results[name] = copy.copy(res) for name in databases: - self.logging.info("Found %s in %s" % (len(results[name]), name)) + self.services.logging.info("Found %s in %s" % (len(results[name]), name)) return results def getInteractionCounter(self, query): @@ -587,7 +587,7 @@ def knownName(self, data): """ - self.logging.info("converting data into known names") + self.services.logging.info("converting data into known names") idsA = [x[0].replace('"', "") for x in data] idsB = [x[1].replace('"', "") for x in data] # extract the first and second ID but let us check if it is part of a @@ -613,10 +613,10 @@ def knownName(self, data): if len(valid_dbs) >= 1: idsA[i] = valid_dbs[0][0] + ":" + valid_dbs[0][1] else: - self.logging.debug("none of the DB for this entry (%s) are available" % (entry)) + self.services.logging.debug("none of the DB for this entry (%s) are available" % (entry)) idsA[i] = "?" + dbs[0] + ":" + IDs[0] except: - self.logging.info("Could not extract name from %s" % entry) + self.services.logging.info("Could not extract name from %s" % entry) idsA[i] = "??:" + entry # we add a : so that we are sure that a split(":") will work # the second ID for i, entry in enumerate(idsB): @@ -628,19 +628,19 @@ def knownName(self, data): if len(valid_dbs) >= 1: idsB[i] = valid_dbs[0][0] + ":" + valid_dbs[0][1] else: - self.logging.debug("none of the DB (%s) for this entry are available" % (entry)) + self.services.logging.debug("none of the DB (%s) for this entry are available" % (entry)) idsB[i] = "?" + dbs[0] + ":" + IDs[0] except: - self.logging.info("Could not extract name from %s" % entry) + self.services.logging.info("Could not extract name from %s" % entry) idsB[i] = "??:" + entry countA = len([x for x in idsA if x.startswith("?")]) countB = len([x for x in idsB if x.startswith("?")]) if countA + countB > 0: - self.logging.warning("%s ids out of %s were not identified" % (countA + countB, len(idsA) * 2)) + self.services.logging.warning("%s ids out of %s were not identified" % (countA + countB, len(idsA) * 2)) print(set([x.split(":")[0] for x in idsA if x.startswith("?")])) print(set([x.split(":")[0] for x in idsB if x.startswith("?")])) - self.logging.info("knownName done") + self.services.logging.info("knownName done") return idsA, idsB def preCleaning(self, data): @@ -656,7 +656,7 @@ def postCleaningAll(self, data, keep_only="HUMAN", flatten=True, verbose=True): """ results = {} for k in data.keys(): - self.logging.info("Post cleaning %s" % k) + self.services.logging.info("Post cleaning %s" % k) ret = self.postCleaning(data[k], keep_only="HUMAN", verbose=verbose) if len(ret): results[k] = ret @@ -708,12 +708,12 @@ def postCleaning( def convertAll(self, data): results = {} for k in data.keys(): - self.logging.info("Analysing %s" % k) + self.services.logging.info("Analysing %s" % k) results[k] = self.convert(data[k], db=k) return results def convert(self, data, db=None): - self.logging.debug("converting the database %s" % db) + self.services.logging.debug("converting the database %s" % db) idsA, idsB = self.knownName(data) mapping = self.mappingOneDB(data) results = [] @@ -739,7 +739,7 @@ def convert(self, data, db=None): def mappingOneDB(self, data): query = {} - self.logging.debug("converting IDs with proper DB name (knownName function)") + self.services.logging.debug("converting IDs with proper DB name (knownName function)") entriesA, entriesB = self.knownName(data) # idsA and B contains list of a single identifier of the form db:id # the db is known from _mapping.uniprot otherwise it is called "unknown" @@ -788,7 +788,7 @@ def mappingOneDB(self, data): DBname = self._mapping_uniprot[k] if DBname is not None: - self.logging.warning("Request sent to uniprot for %s database (%s/%s)" % (DBname, counter, N)) + self.services.logging.warning("Request sent to uniprot for %s database (%s/%s)" % (DBname, counter, N)) res = self.uniprot.mapping(fr=DBname, to="ID", query=" ".join(this_query)) for x in this_query: if x not in res: # was not found @@ -801,7 +801,7 @@ def mappingOneDB(self, data): if len(res[x]) == 1: mapping[x] = res[x][0] else: - self.logging.warning("psicquic mapping found more than 1 id. keep first one") + self.services.logging.warning("psicquic mapping found more than 1 id. keep first one") mapping[x] = res[x][0] else: for x in this_query: diff --git a/src/bioservices/unichem.py b/src/bioservices/unichem.py index 3c97343f..4476f60b 100644 --- a/src/bioservices/unichem.py +++ b/src/bioservices/unichem.py @@ -96,7 +96,7 @@ class UniChem: res['compounds'][0] - .. changed:: version 1.9. drop xml parser. + .. versionchanged:: version 1.9. drop xml parser. """ @@ -384,6 +384,8 @@ def get_images(self, uci, filename=None): .. plot:: + from bioservices import UniChem + u = UniChem() res = u.get_images('304698', filename='test.svg') """ diff --git a/test/webservices/test_chembl.py b/test/webservices/test_chembl.py index 60ee058f..b318a565 100644 --- a/test/webservices/test_chembl.py +++ b/test/webservices/test_chembl.py @@ -2,7 +2,6 @@ import pytest import os -skiptravis = pytest.mark.skipif("TRAVIS_PYTHON_VERSION" in os.environ, reason="On travis") SMILE = "CC(=O)Oc1ccccc1C(=O)O" @@ -95,7 +94,7 @@ def test_activity(chembl): "mechanism", "metabolism", "molecule_form", - "protein_class", + #"protein_class", "source", "target", "target_component", @@ -119,8 +118,7 @@ def test_ATC(chembl): # SEARCHES ------------------ -@skiptravis -def test_search_protein_class(chembl): +def _test_search_protein_class(chembl): res1715 = chembl.get_protein_class(1715) # no good example. This returns noting but at least calls the method chembl.search_protein_class("CAMK") diff --git a/test/webservices/test_kegg.py b/test/webservices/test_kegg.py index 679d3d63..582cfffe 100644 --- a/test/webservices/test_kegg.py +++ b/test/webservices/test_kegg.py @@ -83,32 +83,32 @@ def test_parse_kgml_pathway(kegg): @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids1(kegg): - assert kegg.enzymeIds[0].startswith("ec") + assert kegg.enzymeIds[0].startswith("1.") @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids2(kegg): - assert kegg.compoundIds[0].startswith("cpd") + assert kegg.compoundIds[0].startswith("C") @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids3(kegg): - assert kegg.glycanIds[0].startswith("gl") + assert kegg.glycanIds[0].startswith("G") @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids4(kegg): - assert kegg.reactionIds[0].startswith("rn") + assert kegg.reactionIds[0].startswith("R") @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids5(kegg): - assert kegg.drugIds[0].startswith("dr") + assert kegg.drugIds[0].startswith("D") @pytest.mark.flaky(max_runs=3, min_passes=1) def test_ids6(kegg): - assert kegg.koIds[0].startswith("ko") + assert kegg.koIds[0].startswith("K") @pytest.mark.flaky(max_runs=3, min_passes=1) diff --git a/test/webservices/test_pride.py b/test/webservices/test_pride.py index 2ea4c500..ecdd5be1 100644 --- a/test/webservices/test_pride.py +++ b/test/webservices/test_pride.py @@ -1,8 +1,6 @@ from bioservices import PRIDE -import pytest import os - -pytestmark = pytest.mark.skipif("TRAVIS_PYTHON_VERSION" in os.environ, reason="On travis") +import pytest p = PRIDE() @@ -43,7 +41,8 @@ def test_stats(): assert "SUBMISSIONS_PER_YEAR" in p.get_stats() p.get_stats("SUBMISSIONS_PER_YEAR") - +@pytest.mark.xfail(reason="too slow", method="thread") +@pytest.mark.timeout(30) def test_peptide(): res = p.get_peptide_evidence("PXD016700") assert res["_embedded"]