# HG changeset patch
# User gga
# Date 1505123527 14400
# Node ID a19926451daa37ecc2c54ec324f01b00dcde5cfd
planemo upload for repository https://github.com/galaxy-genome-annotation/galaxy-tools/tree/master/tools/tripal commit f745b23c84a615bf434d717c8c0e553a012f0268
diff -r 000000000000 -r a19926451daa analysis_load_interpro.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/analysis_load_interpro.xml Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,95 @@
+
+
+ into Tripal
+
+ macros.xml
+
+
+
+ $results
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `_ module must be installed and configured on the Tripal instance.
+
+ @HELP@
+ ]]>
+
+
diff -r 000000000000 -r a19926451daa macros.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,215 @@
+
+
+
+
+ python-tripal
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0.4
+
+
+
+ 10.1093/database/bat075
+
+
+
+
+
+ `_
+
+ `Tripal REST API module `_: a Tripal module required to use these galaxy tools
+ ]]>
+
+ \$GALAXY_TRIPAL_SHARED_DIR
+
+ '.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'
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 000000000000 -r a19926451daa test-data/blast.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/blast.xml Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,68 @@
+
+
+
+ blastx
+ blastx 2.2.25 [Feb-01-2011]
+ ~Reference: Altschul, Stephen F., Thomas L. Madden, Alejandro A. Schaffer, ~Jinghui Zhang, Zheng Zhang, Webb Miller, and David J. Lipman (1997), ~"Gapped BLAST and PSI-BLAST: a new generation of protein database search~programs", Nucleic Acids Res. 25:3389-3402.
+ /scratch/mainlab/data/lib/nr
+ lcl|1_0
+ orange1.1g015632m PAC:18136217 (mRNA) Citrus sinensis
+ 2075
+
+
+ BLOSUM62
+ 1e-06
+ 11
+ 1
+ F
+
+
+
+
+ 1
+ lcl|1_0
+ orange1.1g015632m PAC:18136217 (mRNA) Citrus sinensis
+ 2075
+
+
+ 1
+ gi|224068663|ref|XP_002302794.1|
+ predicted protein [Populus trichocarpa] >gi|222844520|gb|EEE82067.1| predicted protein [Populus trichocarpa]
+ XP_002302794
+ 409
+
+
+ 1
+ 792.727
+ 2046
+ 0
+ 559
+ 1767
+ 1
+ 409
+ 1
+ 387
+ 394
+ 6
+ 409
+ MASVSVVPASG------NTVGVDRLPEEMNDMKIRDDKEMEATVVDGNGTEAGHIIVTTIGGKNGQPKQTISYMAERVVGHGSFGVVFQAKCLETGEAVAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPETVHRVIKHHYKMSQRMPLIYVKLYFYQICRALAYIHNTIGVCHRDIKPQNLLVNPHTHQLKLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYTAAIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIFQKRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPNTRLPNGRFLPPLFNFKPHELKGVPVDMLVKLIPEHARKQCAFLGL
+ MASVSVVPASGLRDTLGNTTGVDKLPEEMNDMKISDDKEMEAAVVDGNGTETGHIIVTTIGGKNGQPKQTISYMAERVVGHGSFGLVFQAKCLETGETVAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPETIHRVIKHYYKMSQRMPLIYVKLYFYQICRALAYIHNSIGVCHRDIKPQNLLVNPHTHQVKLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYTTAIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIFHKRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPNARLPNGRILPPLFNFKPHELKGVPVEMLVKLIPEHARKQCAFLGL
+ MASVSVVPASG NT GVD+LPEEMNDMKI DDKEMEA VVDGNGTE GHIIVTTIGGKNGQPKQTISYMAERVVGHGSFG+VFQAKCLETGE VAIKKVLQDKRYKNRELQTMRLLDHPNVVSLKHCFFSTTEKDELYLNLVLEYVPET+HRVIKH+YKMSQRMPLIYVKLYFYQICRALAYIHN+IGVCHRDIKPQNLLVNPHTHQ+KLCDFGSAKVLVKGEPNISYICSRYYRAPELIFGATEYT AIDIWSAGCVLAELLLGQPLFPGESGVDQLVEIIKVLGTPTREEIKCMNPNYTEFKFPQIKAHPWHKIF KRMPPEAVDLVSRLLQYSPNLRSTALEALIHPFFDELRDPN RLPNGR LPPLFNFKPHELKGVPV+MLVKLIPEHARKQCAFLGL
+
+
+
+
+
+
+ 18996442
+ 6510958228
+ 0
+ 0
+ 0.041
+ 0.267
+ 0.14
+
+
+
+
+
diff -r 000000000000 -r a19926451daa test-data/blast2go.gaf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/blast2go.gaf Mon Sep 11 05:52:07 2017 -0400
@@ -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
diff -r 000000000000 -r a19926451daa test-data/citrus_genome.fasta
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/citrus_genome.fasta Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,10 @@
+>scaffold00001 length=5927163
+TTTTGTATTCTATGTCCTCTGATCTTTATACTTCTTCATTTTGTCTTTGCAAGAACCGGA
+ATTATGGGTACATCACAAATTCTCTAGGTGTGACTTGTGTTGTGGGGCCTTTTTTTtACA
+TTTCCATATTGCAAGTATTTTTTTGCTACCATTGGTATATTTGTCTGTTAAAATCAATCT
+GCTTTCACTTATGTTCGTGCGTTCTTGTTCCCTCGCCTTGCAATTGCATATCTCAAATTA
+TCTTTCTTACTTTGATTTAGATGGCCAAGGTTTTAAGCTAACTTTTTACAATGCCAATTT
+TTAAATGGTTTTCTAATGCTGTTCAAAGTTGCAGCCTTTACTTCGTATATTTGTCAGGTT
+CTGACGGGTGCGGTCGGCGGCGGGGGCTATAGCATGCGGTCTCGAGAGCCGCAAAGAAAA
+ATGGGTGGTTTTCCCGGTTTCGGCCATAACTCGTGATCGGGGCCTCCGATTCTGGTTCCG
+TTTCGTCCCACGGGACCAGCCGGGCGGGGGCATCGGATTGCAAAAGTCTTTAAATTTGAA
diff -r 000000000000 -r a19926451daa test-data/interpro.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/interpro.xml Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 000000000000 -r a19926451daa test-data/sample.gff3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/sample.gff3 Mon Sep 11 05:52:07 2017 -0400
@@ -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
diff -r 000000000000 -r a19926451daa tripal.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tripal.py Mon Sep 11 05:52:07 2017 -0400
@@ -0,0 +1,503 @@
+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.
+
+ 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