changeset 0:c896d510ebd8 draft

planemo upload for repository https://github.com/galaxy-genome-annotation/galaxy-tools/tree/master/tools/tripal commit 869e5fd8535deca8325777efcd31c70a514b582a
author gga
date Mon, 25 Feb 2019 06:30:27 -0500
parents
children 7f4be07e1f7a
files README.rst feature_delete_orphans.xml macros.xml test-data/blast.xml test-data/blast2go.gaf test-data/citrus_genome.fasta test-data/interpro.xml test-data/sample.gff3 tripal.py
diffstat 9 files changed, 915 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.rst	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,45 @@
+Galaxy-tripal
+=============
+
+Galaxy tools to interface with Tripal using python-tripal
+
+Dependencies
+------------
+
+You will need to install some python modules in the Galaxy virtualenv for these
+tools to be fully functional:
+
+.. code:: bash
+
+    . /path/to/galaxy/.venv/bin/activate
+    pip install future tripal
+    deactivate
+
+Environment
+-----------
+
+The following environment variables must be set:
+
++--------------------------------+-----------------------------------------------------------+
+| ENV                            | Use                                                       |
++================================+===========================================================+
+| ``$GALAXY_TRIPAL_URL``         | The URL at which Tripal is accessible, internal to Galaxy |
+|                                | and where the tools run. Must be absolute, with FQDN and  |
+|                                | protocol.                                                 |
++--------------------------------+-----------------------------------------------------------+
+| ``$GALAXY_TRIPAL_USER``        | The admin user which Galaxy should use to talk to Tripal. |
+|                                |                                                           |
++--------------------------------+-----------------------------------------------------------+
+| ``$GALAXY_TRIPAL_PASSWORD``    | The password for the admin user.                          |
+|                                |                                                           |
+|                                |                                                           |
++--------------------------------+-----------------------------------------------------------+
+| ``$GALAXY_TRIPAL_SHARED_DIR``  | Directory shared between Galaxy and Tripal, used to       |
+|                                | exchange data files.                                      |
++--------------------------------+-----------------------------------------------------------+
+
+
+License
+-------
+
+All python scripts and wrappers are licensed under MIT license.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/feature_delete_orphans.xml	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<tool id="feature_delete_orphans" name="Delete orphan features" version="@WRAPPER_VERSION@.0">
+ <description>from Tripal</description>
+    <macros>
+        <import>macros.xml</import>
+    </macros>
+    <expand macro="requirements"/>
+    <command detect_errors="aggressive"><![CDATA[
+@AUTH@
+
+tripaille feature delete_orphans
+
+&&
+
+echo "Data loaded" > $results
+]]></command>
+    <inputs>
+    </inputs>
+    <outputs>
+        <data format="txt" name="results"/>
+    </outputs>
+    <help>
+Delete orphans Drupal feature nodes
+
+@HELP@
+    </help>
+</tool>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,224 @@
+<?xml version="1.0"?>
+<macros>
+    <xml name="requirements">
+        <requirements>
+            <requirement type="package" version="3.2">python-tripal</requirement>
+            <yield/>
+        </requirements>
+    </xml>
+
+    <xml name="stdio">
+        <stdio>
+            <regex level="fatal" match="Exception:" source="stderr" />
+            <regex level="fatal" match="error" source="stderr" />
+            <exit_code range="1:" />
+        </stdio>
+    </xml>
+
+    <token name="@WRAPPER_VERSION@">3.2</token>
+
+    <xml name="citation">
+        <citations>
+            <citation type="doi">10.1093/database/bat075</citation>
+        </citations>
+    </xml>
+
+    <token name="@HELP_OVERVIEW@"><![CDATA[
+        **Python-tripal Overview**
+
+        Python-tripal provides several tools allowing to load data into a remote Chado-based Tripal database.
+        The tripal_rest_api Tripal module must be installed on the remote server to use these tools.
+    ]]></token>
+
+    <token name="@HELP@"><![CDATA[
+        **Useful Links**
+
+        `Tripal project website <http://tripal.info/>`_
+
+        `Tripal REST API module <http://github.com/abretaud/tripal_rest_api>`_: a Tripal module required to use these galaxy tools
+    ]]></token>
+
+    <token name="@DATA_DIR@">\$GALAXY_TRIPAL_SHARED_DIR</token>
+
+    <token name="@AUTH@"><![CDATA[
+        echo "__default: local" > '.auth.yml' &&
+        echo "local:" >> '.auth.yml' &&
+        echo "    tripal_url: \"\$GALAXY_TRIPAL_URL\"" >> '.auth.yml' &&
+        echo "    username: \"\$GALAXY_TRIPAL_USER\"" >> '.auth.yml' &&
+        echo "    password: \"\$GALAXY_TRIPAL_PASSWORD\"" >> '.auth.yml' &&
+
+        TRIPAILLE_GLOBAL_CONFIG_PATH='.auth.yml'
+    ]]></token>
+
+    <xml name="wait_for">
+        <param name="wait_for"
+               type="data"
+               format="data"
+               optional="true"
+               label="Run this only after the following dataset is ready"
+               help="Use this if you want to delay the job execution until some data is already loaded. The selected dataset will not be used for anything else."/>
+    </xml>
+
+    <xml name="test_result">
+        <assert_stderr>
+            <has_text text="MissingSchema" />
+        </assert_stderr>
+    </xml>
+
+    <xml name="analysis">
+        <section name="analysis" title="Analysis" expanded="True">
+            <param name="name"
+                   type="text"
+                   label="The analysis name [mandatory]">
+                <expand macro="sanitized"/>
+            </param>
+
+            <param name="program"
+                   type="text"
+                   label="Program name [mandatory]"
+                   help="Name of the program that was used to perform this analysis">
+                <expand macro="sanitized"/>
+            </param>
+            <param name="program_version"
+                   type="text"
+                   label="Program version [mandatory]"
+                   help="Version of the program that was used to perform this analysis"/>
+            <param name="source"
+                   type="text"
+                   label="Source name [mandatory]"
+                   help="Where this analysis comes from">
+                <expand macro="sanitized"/>
+            </param>
+
+            <param name="source_version"
+                   argument="--sourceversion"
+                   type="text"
+                   optional="True"
+                   label="Source version" />
+            <param name="source_uri"
+                   argument="--sourceuri"
+                   type="text"
+                   optional="True"
+                   label="Source URI"
+                   help="URI where source data was retrieved" />
+            <param name="algorithm"
+                   argument="--algorithm"
+                   type="text"
+                   label="Algorithm"
+                   optional="True"
+                   help="Algorithm of the program that was used to perform this analysis" />
+            <param name="description"
+                   argument="--description"
+                   type="text"
+                   optional="True"
+                   label="Analysis description">
+                <expand macro="sanitized"/>
+            </param>
+            <param name="date"
+                   argument="--date_executed"
+                   type="text"
+                   optional="True"
+                   label="Execution date"
+                   help="Format: yyyy-mm-dd  Default: Today">
+                <validator type="regex" message="Date in YYYY-MM-DD format">^[0-9]{4}-[0-9]{2}-[0-9]{2}$</validator>
+            </param>
+        </section>
+    </xml>
+
+    <xml name="feature_rel">
+        <param name="rel_subject_re"
+               argument="--rel-subject-re"
+               type="text"
+               label="Regular expression to extract the unique name of the parent feature"
+               help="this regex will be applied on the fasta definition line to generate the unique name of the parent feature">
+            <expand macro="sanitized"/>
+        </param>
+
+        <param name="rel_subject_type"
+               argument="--rel-subject-type"
+               type="text"
+               label="Sequence type of the parent"
+               help="this should be a Sequence Ontology term" />
+    </xml>
+
+    <xml name="match_type">
+        <param name="match_type"
+               argument="--match-type"
+               type="select"
+               label="Match type for already loaded features">
+            <option value="uniquename" selected="true">Unique name</option>
+            <option value="name">Name</option>
+        </param>
+    </xml>
+
+    <xml name="matching">
+        <section name="matching" title="Feature matching" expanded="True">
+            <param name="query_type"
+                   type="text"
+                   label="The feature type of the blast query"
+                   help="It must be a valid Sequence Ontology term. e.g. 'contig', 'gene', 'mRNA', 'polypeptide'" />
+
+            <param name="query_uniquename"
+                   type="boolean"
+                   checked="false"
+                   truevalue="--query_uniquename"
+                   falsevalue=""
+                   label="Find blast query features using their Unique name"
+                   help="Feature name will be used otherwise" />
+
+            <param name="query_re"
+                   type="text"
+                   optional="true"
+                   label="Regular expression to extract the feature name from the blast query name"
+                   help="leave empty if the first word in query name is sufficient">
+                <expand macro="sanitized"/>
+            </param>
+        </section>
+    </xml>
+
+    <xml name="sanitized">
+        <sanitizer>
+            <valid initial="string.printable">
+                <remove value="&apos;"/>
+            </valid>
+            <mapping initial="none">
+                <add source="&apos;" target="&apos;&quot;&apos;&quot;&apos;"/>
+                <add source="(" target="\("/>
+                <add source=")" target="\)"/>
+            </mapping>
+        </sanitizer>
+    </xml>
+
+    <token name="@MATCHING@"><![CDATA[
+        #if str($matching.query_re):
+            --query_re '${matching.query_re}'
+        #end if
+
+        $matching.query_uniquename
+
+        --query_type '$matching.query_type'
+    ]]></token>
+
+    <token name="@ANALYSIS@"><![CDATA[
+        #if $analysis.algorithm:
+            --algorithm '$analysis.algorithm'
+        #end if
+        #if $analysis.source_version:
+            --sourceversion '$analysis.source_version'
+        #end if
+        #if $analysis.source_uri:
+            --sourceuri '$analysis.source_uri'
+        #end if
+        #if $analysis.description:
+            --description '$analysis.description'
+        #end if
+        #if $analysis.date:
+            --date_executed '$analysis.date'
+        #end if
+
+        '$analysis.name'
+        '$analysis.program'
+        '$analysis.program_version'
+        '$analysis.source'
+    ]]></token>
+</macros>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/blast.xml	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!DOCTYPE BlastOutput PUBLIC "-//NCBI//NCBI BlastOutput/EN" "http://www.ncbi.nlm.nih.gov/dtd/NCBI_BlastOutput.dtd">
+<BlastOutput>
+  <BlastOutput_program>blastx</BlastOutput_program>
+  <BlastOutput_version>blastx 2.2.25 [Feb-01-2011]</BlastOutput_version>
+  <BlastOutput_reference>~Reference: Altschul, Stephen F., Thomas L. Madden, Alejandro A. Schaffer, ~Jinghui Zhang, Zheng Zhang, Webb Miller, and David J. Lipman (1997), ~&quot;Gapped BLAST and PSI-BLAST: a new generation of protein database search~programs&quot;,  Nucleic Acids Res. 25:3389-3402.</BlastOutput_reference>
+  <BlastOutput_db>/scratch/mainlab/data/lib/nr</BlastOutput_db>
+  <BlastOutput_query-ID>lcl|1_0</BlastOutput_query-ID>
+  <BlastOutput_query-def>orange1.1g015632m PAC:18136217 (mRNA) Citrus sinensis</BlastOutput_query-def>
+  <BlastOutput_query-len>2075</BlastOutput_query-len>
+  <BlastOutput_param>
+    <Parameters>
+      <Parameters_matrix>BLOSUM62</Parameters_matrix>
+      <Parameters_expect>1e-06</Parameters_expect>
+      <Parameters_gap-open>11</Parameters_gap-open>
+      <Parameters_gap-extend>1</Parameters_gap-extend>
+      <Parameters_filter>F</Parameters_filter>
+    </Parameters>
+  </BlastOutput_param>
+  <BlastOutput_iterations>
+    <Iteration>
+      <Iteration_iter-num>1</Iteration_iter-num>
+      <Iteration_query-ID>lcl|1_0</Iteration_query-ID>
+      <Iteration_query-def>orange1.1g015632m PAC:18136217 (mRNA) Citrus sinensis</Iteration_query-def>
+      <Iteration_query-len>2075</Iteration_query-len>
+      <Iteration_hits>
+        <Hit>
+          <Hit_num>1</Hit_num>
+          <Hit_id>gi|224068663|ref|XP_002302794.1|</Hit_id>
+          <Hit_def>predicted protein [Populus trichocarpa] &gt;gi|222844520|gb|EEE82067.1| predicted protein [Populus trichocarpa]</Hit_def>
+          <Hit_accession>XP_002302794</Hit_accession>
+          <Hit_len>409</Hit_len>
+          <Hit_hsps>
+            <Hsp>
+              <Hsp_num>1</Hsp_num>
+              <Hsp_bit-score>792.727</Hsp_bit-score>
+              <Hsp_score>2046</Hsp_score>
+              <Hsp_evalue>0</Hsp_evalue>
+              <Hsp_query-from>559</Hsp_query-from>
+              <Hsp_query-to>1767</Hsp_query-to>
+              <Hsp_hit-from>1</Hsp_hit-from>
+              <Hsp_hit-to>409</Hsp_hit-to>
+              <Hsp_query-frame>1</Hsp_query-frame>
+              <Hsp_identity>387</Hsp_identity>
+              <Hsp_positive>394</Hsp_positive>
+              <Hsp_gaps>6</Hsp_gaps>
+              <Hsp_align-len>409</Hsp_align-len>
+              <Hsp_qseq>MASVSVVPASG------NTVGVDRLPEEMNDMKIRDDKEMEATVVDGNGTEAGHIIVTTIGGKNGQPKQTISYMAERVVGHGSFGVVFQAKCLETGEAVAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPETVHRVIKHHYKMSQRMPLIYVKLYFYQICRALAYIHNTIGVCHRDIKPQNLLVNPHTHQLKLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYTAAIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIFQKRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPNTRLPNGRFLPPLFNFKPHELKGVPVDMLVKLIPEHARKQCAFLGL</Hsp_qseq>
+              <Hsp_hseq>MASVSVVPASGLRDTLGNTTGVDKLPEEMNDMKISDDKEMEAAVVDGNGTETGHIIVTTIGGKNGQPKQTISYMAERVVGHGSFGLVFQAKCLETGETVAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPETIHRVIKHYYKMSQRMPLIYVKLYFYQICRALAYIHNSIGVCHRDIKPQNLLVNPHTHQVKLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYTTAIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIFHKRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPNARLPNGRILPPLFNFKPHELKGVPVEMLVKLIPEHARKQCAFLGL</Hsp_hseq>
+              <Hsp_midline>MASVSVVPASG      NT GVD+LPEEMNDMKI DDKEMEA VVDGNGTE GHIIVTTIGGKNGQPKQTISYMAERVVGHGSFG+VFQAKCLETGE VAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPET+HRVIKH+YKMSQRMPLIYVKLYFYQICRALAYIHN+IGVCHRDIKPQNLLVNPHTHQ+KLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYT AIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIF KRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPN RLPNGR LPPLFNFKPHELKGVPV+MLVKLIPEHARKQCAFLGL</Hsp_midline>
+            </Hsp>
+          </Hit_hsps>
+        </Hit>
+      </Iteration_hits>
+      <Iteration_stat>
+        <Statistics>
+          <Statistics_db-num>18996442</Statistics_db-num>
+          <Statistics_db-len>6510958228</Statistics_db-len>
+          <Statistics_hsp-len>0</Statistics_hsp-len>
+          <Statistics_eff-space>0</Statistics_eff-space>
+          <Statistics_kappa>0.041</Statistics_kappa>
+          <Statistics_lambda>0.267</Statistics_lambda>
+          <Statistics_entropy>0.14</Statistics_entropy>
+        </Statistics>
+      </Iteration_stat>
+    </Iteration>
+  </BlastOutput_iterations>
+</BlastOutput>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/blast2go.gaf	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,6 @@
+!gaf-version: 2.1
+	gi|328696447|ref|XP_003240026.1|			GO:0016021												
+	gi|328696447|ref|XP_003240026.1|			GO:0006511												
+	gi|328696447|ref|XP_003240026.1|			GO:0030145												
+	gi|328696447|ref|XP_003240026.1|			GO:0004803												
+	gi|328696447|ref|XP_003240026.1|			GO:0004177										
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/citrus_genome.fasta	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,10 @@
+>scaffold00001  length=5927163
+TTTTGTATTCTATGTCCTCTGATCTTTATACTTCTTCATTTTGTCTTTGCAAGAACCGGA
+ATTATGGGTACATCACAAATTCTCTAGGTGTGACTTGTGTTGTGGGGCCTTTTTTTtACA
+TTTCCATATTGCAAGTATTTTTTTGCTACCATTGGTATATTTGTCTGTTAAAATCAATCT
+GCTTTCACTTATGTTCGTGCGTTCTTGTTCCCTCGCCTTGCAATTGCATATCTCAAATTA
+TCTTTCTTACTTTGATTTAGATGGCCAAGGTTTTAAGCTAACTTTTTACAATGCCAATTT
+TTAAATGGTTTTCTAATGCTGTTCAAAGTTGCAGCCTTTACTTCGTATATTTGTCAGGTT
+CTGACGGGTGCGGTCGGCGGCGGGGGCTATAGCATGCGGTCTCGAGAGCCGCAAAGAAAA
+ATGGGTGGTTTTCCCGGTTTCGGCCATAACTCGTGATCGGGGCCTCCGATTCTGGTTCCG
+TTTCGTCCCACGGGACCAGCCGGGCGGGGGCATCGGATTGCAAAAGTCTTTAAATTTGAA
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/interpro.xml	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,12 @@
+<interpro_matches>
+
+   <protein id="orange1.1g022799m_6_ORF4" length="79" crc64="D3F0B609CB0B9D28" >
+	<interpro id="noIPR" name="unintegrated" type="unintegrated">
+	  <match id="seg" name="seg" dbname="SEG">
+	    <location start="11" end="17" score="NA" status="?" evidence="Seg" />
+	    <location start="54" end="78" score="NA" status="?" evidence="Seg" />
+	  </match>
+	</interpro>
+   </protein>
+
+</interpro_matches>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/sample.gff3	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,21 @@
+##gff-version 3
+##sequence-region scaffold00001 4058460 4062210
+scaffold00001	phytozome6	supercontig	1	5927163	.	.	.	Name=scaffold00001;ID=scaffold00001
+scaffold00001	phytozome6	gene	4058460	4062210	.	+	.	ID=orange1.1g015632m.g;Name=orange1.1g015632m.g
+scaffold00001	phytozome6	mRNA	4058460	4062210	.	+	.	ID=PAC:18136217;Name=orange1.1g015632m;PACid=18136217;Parent=orange1.1g015632m.g
+scaffold00001	phytozome6	five_prime_UTR	4058460	4058898	.	+	.	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	five_prime_UTR	4059019	4059074	.	+	.	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	five_prime_UTR	4059172	4059234	.	+	.	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4059235	4059330	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4059422	4059514	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4059600	4059659	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4059790	4060062	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4060285	4060359	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4060480	4060536	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4060625	4060765	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4060857	4060907	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4061250	4061345	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4061417	4061500	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4061617	4061719	.	+	0	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	CDS	4061823	4061905	.	+	2	Parent=PAC:18136217;PACid=18136217
+scaffold00001	phytozome6	three_prime_UTR	4061906	4062210	.	+	.	Parent=PAC:18136217;PACid=18136217
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tripal.py	Mon Feb 25 06:30:27 2019 -0500
@@ -0,0 +1,502 @@
+import collections
+import os
+import time
+from abc import abstractmethod
+
+import tripal
+
+
+#############################################
+#      BEGIN IMPORT OF CACHING LIBRARY      #
+#############################################
+# This code is licensed under the MIT       #
+# License and is a copy of code publicly    #
+# available in rev.                         #
+# e27332bc82f4e327aedaec17c9b656ae719322ed  #
+# of https://github.com/tkem/cachetools/    #
+#############################################
+class DefaultMapping(collections.MutableMapping):
+
+    __slots__ = ()
+
+    @abstractmethod
+    def __contains__(self, key):  # pragma: nocover
+        return False
+
+    @abstractmethod
+    def __getitem__(self, key):  # pragma: nocover
+        if hasattr(self.__class__, '__missing__'):
+            return self.__class__.__missing__(self, key)
+        else:
+            raise KeyError(key)
+
+    def get(self, key, default=None):
+        if key in self:
+            return self[key]
+        else:
+            return default
+
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+        if key in self:
+            value = self[key]
+            del self[key]
+        elif default is self.__marker:
+            raise KeyError(key)
+        else:
+            value = default
+        return value
+
+    def setdefault(self, key, default=None):
+        if key in self:
+            value = self[key]
+        else:
+            self[key] = value = default
+        return value
+
+
+DefaultMapping.register(dict)
+
+
+class _DefaultSize(object):
+    def __getitem__(self, _):
+        return 1
+
+    def __setitem__(self, _, value):
+        assert value == 1
+
+    def pop(self, _):
+        return 1
+
+
+class Cache(DefaultMapping):
+    """Mutable mapping to serve as a simple cache or cache base class."""
+
+    __size = _DefaultSize()
+
+    def __init__(self, maxsize, missing=None, getsizeof=None):
+        if missing:
+            self.__missing = missing
+        if getsizeof:
+            self.__getsizeof = getsizeof
+            self.__size = dict()
+        self.__data = dict()
+        self.__currsize = 0
+        self.__maxsize = maxsize
+
+    def __repr__(self):
+        return '%s(%r, maxsize=%r, currsize=%r)' % (
+            self.__class__.__name__,
+            list(self.__data.items()),
+            self.__maxsize,
+            self.__currsize,
+        )
+
+    def __getitem__(self, key):
+        try:
+            return self.__data[key]
+        except KeyError:
+            return self.__missing__(key)
+
+    def __setitem__(self, key, value):
+        maxsize = self.__maxsize
+        size = self.getsizeof(value)
+        if size > maxsize:
+            raise ValueError('value too large')
+        if key not in self.__data or self.__size[key] < size:
+            while self.__currsize + size > maxsize:
+                self.popitem()
+        if key in self.__data:
+            diffsize = size - self.__size[key]
+        else:
+            diffsize = size
+        self.__data[key] = value
+        self.__size[key] = size
+        self.__currsize += diffsize
+
+    def __delitem__(self, key):
+        size = self.__size.pop(key)
+        del self.__data[key]
+        self.__currsize -= size
+
+    def __contains__(self, key):
+        return key in self.__data
+
+    def __missing__(self, key):
+        value = self.__missing(key)
+        try:
+            self.__setitem__(key, value)
+        except ValueError:
+            pass  # value too large
+        return value
+
+    def __iter__(self):
+        return iter(self.__data)
+
+    def __len__(self):
+        return len(self.__data)
+
+    @staticmethod
+    def __getsizeof(value):
+        return 1
+
+    @staticmethod
+    def __missing(key):
+        raise KeyError(key)
+
+    @property
+    def maxsize(self):
+        """The maximum size of the cache."""
+        return self.__maxsize
+
+    @property
+    def currsize(self):
+        """The current size of the cache."""
+        return self.__currsize
+
+    def getsizeof(self, value):
+        """Return the size of a cache element's value."""
+        return self.__getsizeof(value)
+
+
+class _Link(object):
+
+    __slots__ = ('key', 'expire', 'next', 'prev')
+
+    def __init__(self, key=None, expire=None):
+        self.key = key
+        self.expire = expire
+
+    def __reduce__(self):
+        return _Link, (self.key, self.expire)
+
+    def unlink(self):
+        next = self.next
+        prev = self.prev
+        prev.next = next
+        next.prev = prev
+
+
+class _Timer(object):
+
+    def __init__(self, timer):
+        self.__timer = timer
+        self.__nesting = 0
+
+    def __call__(self):
+        if self.__nesting == 0:
+            return self.__timer()
+        else:
+            return self.__time
+
+    def __enter__(self):
+        if self.__nesting == 0:
+            self.__time = time = self.__timer()
+        else:
+            time = self.__time
+        self.__nesting += 1
+        return time
+
+    def __exit__(self, *exc):
+        self.__nesting -= 1
+
+    def __reduce__(self):
+        return _Timer, (self.__timer,)
+
+    def __getattr__(self, name):
+        return getattr(self.__timer, name)
+
+
+class TTLCache(Cache):
+    """LRU Cache implementation with per-item time-to-live (TTL) value."""
+
+    def __init__(self, maxsize, ttl, timer=time.time, missing=None,
+                 getsizeof=None):
+        Cache.__init__(self, maxsize, missing, getsizeof)
+        self.__root = root = _Link()
+        root.prev = root.next = root
+        self.__links = collections.OrderedDict()
+        self.__timer = _Timer(timer)
+        self.__ttl = ttl
+
+    def __contains__(self, key):
+        try:
+            link = self.__links[key]  # no reordering
+        except KeyError:
+            return False
+        else:
+            return not (link.expire < self.__timer())
+
+    def __getitem__(self, key, cache_getitem=Cache.__getitem__):
+        try:
+            link = self.__getlink(key)
+        except KeyError:
+            expired = False
+        else:
+            expired = link.expire < self.__timer()
+        if expired:
+            return self.__missing__(key)
+        else:
+            return cache_getitem(self, key)
+
+    def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+        with self.__timer as time:
+            self.expire(time)
+            cache_setitem(self, key, value)
+        try:
+            link = self.__getlink(key)
+        except KeyError:
+            self.__links[key] = link = _Link(key)
+        else:
+            link.unlink()
+        link.expire = time + self.__ttl
+        link.next = root = self.__root
+        link.prev = prev = root.prev
+        prev.next = root.prev = link
+
+    def __delitem__(self, key, cache_delitem=Cache.__delitem__):
+        cache_delitem(self, key)
+        link = self.__links.pop(key)
+        link.unlink()
+        if link.expire < self.__timer():
+            raise KeyError(key)
+
+    def __iter__(self):
+        root = self.__root
+        curr = root.next
+        while curr is not root:
+            # "freeze" time for iterator access
+            with self.__timer as time:
+                if not (curr.expire < time):
+                    yield curr.key
+            curr = curr.next
+
+    def __len__(self):
+        root = self.__root
+        curr = root.next
+        time = self.__timer()
+        count = len(self.__links)
+        while curr is not root and curr.expire < time:
+            count -= 1
+            curr = curr.next
+        return count
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        root = self.__root
+        root.prev = root.next = root
+        for link in sorted(self.__links.values(), key=lambda obj: obj.expire):
+            link.next = root
+            link.prev = prev = root.prev
+            prev.next = root.prev = link
+        self.expire(self.__timer())
+
+    def __repr__(self, cache_repr=Cache.__repr__):
+        with self.__timer as time:
+            self.expire(time)
+            return cache_repr(self)
+
+    @property
+    def currsize(self):
+        with self.__timer as time:
+            self.expire(time)
+            return super(TTLCache, self).currsize
+
+    @property
+    def timer(self):
+        """The timer function used by the cache."""
+        return self.__timer
+
+    @property
+    def ttl(self):
+        """The time-to-live value of the cache's items."""
+        return self.__ttl
+
+    def expire(self, time=None):
+        """Remove expired items from the cache."""
+        if time is None:
+            time = self.__timer()
+        root = self.__root
+        curr = root.next
+        links = self.__links
+        cache_delitem = Cache.__delitem__
+        while curr is not root and curr.expire < time:
+            cache_delitem(self, curr.key)
+            del links[curr.key]
+            next = curr.next
+            curr.unlink()
+            curr = next
+
+    def clear(self):
+        with self.__timer as time:
+            self.expire(time)
+            Cache.clear(self)
+
+    def get(self, *args, **kwargs):
+        with self.__timer:
+            return Cache.get(self, *args, **kwargs)
+
+    def pop(self, *args, **kwargs):
+        with self.__timer:
+            return Cache.pop(self, *args, **kwargs)
+
+    def setdefault(self, *args, **kwargs):
+        with self.__timer:
+            return Cache.setdefault(self, *args, **kwargs)
+
+    def popitem(self):
+        """Remove and return the `(key, value)` pair least recently used that
+        has not already expired.
+
+        """
+        with self.__timer as time:
+            self.expire(time)
+            try:
+                key = next(iter(self.__links))
+            except StopIteration:
+                raise KeyError('%s is empty' % self.__class__.__name__)
+            else:
+                return (key, self.pop(key))
+
+    if hasattr(collections.OrderedDict, 'move_to_end'):
+        def __getlink(self, key):
+            value = self.__links[key]
+            self.__links.move_to_end(key)
+            return value
+    else:
+        def __getlink(self, key):
+            value = self.__links.pop(key)
+            self.__links[key] = value
+            return value
+
+
+#############################################
+#       END IMPORT OF CACHING LIBRARY       #
+#############################################
+
+cache = TTLCache(
+    100,  # Up to 100 items
+    1 * 60  # 5 minute cache life
+)
+
+
+def _get_instance():
+    return tripal.TripalInstance(
+        os.environ['GALAXY_TRIPAL_URL'],
+        os.environ['GALAXY_TRIPAL_USER'],
+        os.environ['GALAXY_TRIPAL_PASSWORD']
+    )
+
+
+def list_organisms(*args, **kwargs):
+
+    ti = _get_instance()
+
+    # Key for cached data
+    cacheKey = 'orgs'
+    # We don't want to trust "if key in cache" because between asking and fetch
+    # it might through key error.
+    if cacheKey not in cache:
+        # However if it ISN'T there, we know we're safe to fetch + put in
+        # there.
+        data = _list_organisms(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+    try:
+        # The cache key may or may not be in the cache at this point, it
+        # /likely/ is. However we take no chances that it wasn't evicted between
+        # when we checked above and now, so we reference the object from the
+        # cache in preparation to return.
+        data = cache[cacheKey]
+        return data
+    except KeyError:
+        # If access fails due to eviction, we will fail over and can ensure that
+        # data is inserted.
+        data = _list_organisms(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+
+
+def _list_organisms(ti, *args, **kwargs):
+    # Fetch the orgs.
+    orgs_data = []
+    for org in ti.organism.get_organisms():
+        clean_name = '%s %s' % (org['genus'], org['species'])
+        if org['infraspecific_name']:
+            clean_name += ' (%s)' % (org['infraspecific_name'])
+        orgs_data.append((clean_name, org['organism_id'], False))
+    return orgs_data
+
+
+def list_analyses(*args, **kwargs):
+
+    ti = _get_instance()
+
+    # Key for cached data
+    cacheKey = 'analyses'
+    # We don't want to trust "if key in cache" because between asking and fetch
+    # it might through key error.
+    if cacheKey not in cache:
+        # However if it ISN'T there, we know we're safe to fetch + put in
+        # there.<?xml version="1.0"?>
+
+        data = _list_analyses(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+    try:
+        # The cache key may or may not be in the cache at this point, it
+        # /likely/ is. However we take no chances that it wasn't evicted between
+        # when we checked above and now, so we reference the object from the
+        # cache in preparation to return.
+        data = cache[cacheKey]
+        return data
+    except KeyError:
+        # If access fails due to eviction, we will fail over and can ensure that
+        # data is inserted.
+        data = _list_analyses(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+
+
+def _list_analyses(ti, *args, **kwargs):
+    ans_data = []
+    for an in ti.analysis.get_analyses():
+        ans_data.append((an['name'], an['analysis_id'], False))
+    return ans_data
+
+
+def list_blastdbs(*args, **kwargs):
+
+    ti = _get_instance()
+
+    # Key for cached data
+    cacheKey = 'blastdbs'
+    # We don't want to trust "if key in cache" because between asking and fetch
+    # it might through key error.
+    if cacheKey not in cache:
+        # However if it ISN'T there, we know we're safe to fetch + put in
+        # there.
+        data = _list_blastdbs(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+    try:
+        # The cache key may or may not be in the cache at this point, it
+        # /likely/ is. However we take no chances that it wasn't evicted between
+        # when we checked above and now, so we reference the object from the
+        # cache in preparation to return.
+        data = cache[cacheKey]
+        return data
+    except KeyError:
+        # If access fails due to eviction, we will fail over and can ensure that
+        # data is inserted.
+        data = _list_blastdbs(ti, *args, **kwargs)
+        cache[cacheKey] = data
+        return data
+
+
+def _list_blastdbs(ti, *args, **kwargs):
+    dbs_data = []
+    for db in ti.db.get_dbs():
+        dbs_data.append((db['name'], db['db_id'], False))
+    return dbs_data