Repository 'apollo_delete_features'
hg clone https://toolshed.g2.bx.psu.edu/repos/gga/apollo_delete_features

Changeset 10:df0e4eb2dfa5 (2019-12-02)
Previous changeset 9:2adc3aa47d15 (2019-07-29) Next changeset 11:6c42ea4ab169 (2020-04-14)
Commit message:
"planemo upload for repository https://github.com/galaxy-genome-annotation/galaxy-tools/tree/master/tools/apollo commit 08015be1ee8a784e0619f961aaa724857debfd6f"
modified:
README.rst
create_account.py
create_features_from_gff3.py
create_or_update_organism.py
delete_features.py
delete_features.xml
delete_organism.py
export.py
fetch_organism_jbrowse.py
list_organisms.py
macros.xml
webapollo.py
added:
test-data/arrow.yml
test-data/create_org/output.json
test-data/create_org/output2.json
test-data/dataset_1.dat
test-data/dataset_1_files/data/.htaccess
test-data/dataset_1_files/data/names/02b/9.json
test-data/dataset_1_files/data/names/0e9/3.json
test-data/dataset_1_files/data/names/83f/8.json
test-data/dataset_1_files/data/names/92c/2.json
test-data/dataset_1_files/data/names/cf0/e.json
test-data/dataset_1_files/data/names/f26/8.json
test-data/dataset_1_files/data/names/meta.json
test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz
test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz.tbi
test-data/dataset_1_files/data/seq/genome.fasta
test-data/dataset_1_files/data/seq/genome.fasta.fai
test-data/dataset_1_files/data/seq/refSeqs.json
test-data/dataset_1_files/data/trackList.json
test-data/dataset_1_files/data/tracks.conf
test-data/dataset_1_files/galaxy.xml
test-data/dataset_1_files/jbrowse.conf
test-data/dataset_1_files/jbrowse_conf.json
test-data/export/cdna.fa
test-data/export/cds.fa
test-data/export/out.vcf
test-data/export/pep.fa
test-data/load_gff3/output.tsv
test-data/merlin.gff
test-data/org_remote.tar.gz
removed:
test-data/bad-model.gff3
test-data/good-model.gff3
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 README.rst
--- a/README.rst Mon Jul 29 10:09:19 2019 -0400
+++ b/README.rst Mon Dec 02 05:44:41 2019 -0500
b
@@ -1,27 +1,13 @@
 Galaxy-apollo
 =============
 
-Galaxy tools to interface with Apollo The webapollo.py file is also
-`separately
-available <https://github.com/galaxy-genome-annotation/python-apollo>`__
-as a pip-installable package.
-
-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 six biopython bcbio-gff
-    deactivate
+Galaxy tools to interface with Apollo.
+Uses `python-apollo <https://github.com/galaxy-genome-annotation/python-apollo>`__ for most of it.
 
 Environment
 -----------
 
-The following environment variables must be set:
+The following environment variables can be set:
 
 +--------------------------------+-----------------------------------------------------------+
 | ENV                            | Use                                                       |
@@ -34,15 +20,22 @@
 |                                |                                                           |
 +--------------------------------+-----------------------------------------------------------+
 | ``$GALAXY_WEBAPOLLO_PASSWORD`` | The password for the admin user.                          |
-|                                |                                                           |
-|                                |                                                           |
++--------------------------------+-----------------------------------------------------------+
+| ``$ARROW_GLOBAL_CONFIG_PATH``  | Path to a python-apollo/arrow conf file. Use in place of  |
+|                                | ``$GALAXY_WEBAPOLLO_URL``, ``$GALAXY_WEBAPOLLO_USER``     |
+|                                | and ``$GALAXY_WEBAPOLLO_PASSWORD``.                       |
 +--------------------------------+-----------------------------------------------------------+
 | ``$GALAXY_WEBAPOLLO_EXT_URL``  | May be relative or absolute.                              |
 |                                | The external URL at which Apollo is accessible to end     |
 |                                | users.                                                    |
 +--------------------------------+-----------------------------------------------------------+
 | ``$GALAXY_SHARED_DIR``         | Directory shared between Galaxy and Apollo, used to       |
-|                                | exchange JBrowse instances.                               |
+|                                | exchange JBrowse instances. If not set, JBrowse data will |
+|                                | be zipped and sent to the remote server.                  |
++--------------------------------+-----------------------------------------------------------+
+| ``$GALAXY_APOLLO_ORG_SUFFIX``  | Set to 'id' if you want organism names to be suffixed     |
+|                                | with user id to avoid name collisions. Set to 'email' to  |
+|                                | use user email as suffix. Leave empty for no suffix.      |
 +--------------------------------+-----------------------------------------------------------+
 
 License
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 create_account.py
--- a/create_account.py Mon Jul 29 10:09:19 2019 -0400
+++ b/create_account.py Mon Dec 02 05:44:41 2019 -0500
[
@@ -4,35 +4,30 @@
 import argparse
 import time
 
-from six.moves.builtins import str
-
-from webapollo import PasswordGenerator, WAAuth, WebApolloInstance
+from arrow.apollo import get_apollo_instance
 
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Sample script to add an account via web services')
-    WAAuth(parser)
-
     parser.add_argument('email', help='User Email')
     parser.add_argument('--first', help='First Name', default='Jane')
     parser.add_argument('--last', help='Last Name', default='Aggie')
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
+    wa = get_apollo_instance()
 
-    password = PasswordGenerator(12)
+    password = wa.users._password_generator(12)
     time.sleep(1)
-    users = wa.users.loadUsers()
+    users = wa.users.get_users()
     user = [u for u in users
-            if u.username == args.email]
+            if u['username'] == args.email]
 
     if len(user) == 1:
         # Update name, regen password if the user ran it again
-        userObj = user[0]
-        returnData = wa.users.updateUser(userObj, args.email, args.first, args.last, password)
+        returnData = wa.users.update_user(args.email, args.first, args.last, password)
         print('Updated User\nUsername: %s\nPassword: %s' % (args.email, password))
     else:
-        returnData = wa.users.createUser(args.email, args.first, args.last, password, role='user')
+        returnData = wa.users.create_user(args.email, args.first, args.last, password, role='user')
         print('Created User\nUsername: %s\nPassword: %s' % (args.email, password))
 
     print("Return data: " + str(returnData))
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 create_features_from_gff3.py
--- a/create_features_from_gff3.py Mon Jul 29 10:09:19 2019 -0400
+++ b/create_features_from_gff3.py Mon Dec 02 05:44:41 2019 -0500
[
b'@@ -1,21 +1,19 @@\n #!/usr/bin/env python\n import argparse\n import logging\n-import sys\n-import time\n+\n+from apollo import accessible_organisms\n+from apollo.util import GuessOrg, OrgOrGuess\n \n-from BCBio import GFF\n+from arrow.apollo import get_apollo_instance\n \n-from six.moves.builtins import str\n-\n-from webapollo import GuessOrg, OrgOrGuess, PermissionCheck, WAAuth, WebApolloInstance, featuresToFeatureSchema, retry\n+from webapollo import UserObj, handle_credentials\n logging.basicConfig(level=logging.INFO)\n log = logging.getLogger(__name__)\n \n \n if __name__ == \'__main__\':\n     parser = argparse.ArgumentParser(description=\'Sample script to add an attribute to a feature via web services\')\n-    WAAuth(parser)\n     parser.add_argument(\'email\', help=\'User Email\')\n     parser.add_argument(\'--source\', help=\'URL where the input dataset can be found.\')\n     OrgOrGuess(parser)\n@@ -23,165 +21,25 @@\n     parser.add_argument(\'gff3\', type=argparse.FileType(\'r\'), help=\'GFF3 file\')\n     args = parser.parse_args()\n \n-    wa = WebApolloInstance(args.apollo, args.username, args.password)\n+    wa = get_apollo_instance()\n     # User must have an account\n-    gx_user = wa.users.assertOrCreateUser(args.email)\n+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))\n+    handle_credentials(gx_user)\n \n     # Get organism\n     org_cn = GuessOrg(args, wa)\n     if isinstance(org_cn, list):\n         org_cn = org_cn[0]\n \n-    if not PermissionCheck(gx_user, org_cn, "WRITE"):\n-        raise Exception("Action not permitted")\n-    org = wa.organisms.findOrganismByCn(org_cn)\n-\n-    bad_quals = [\'date_creation\', \'source\', \'owner\', \'date_last_modified\', \'Name\', \'ID\']\n-\n-    sys.stdout.write(\'# \')\n-    sys.stdout.write(\'\\t\'.join([\'Feature ID\', \'Apollo ID\', \'Success\', \'Messages\']))\n-    sys.stdout.write(\'\\n\')\n-    # print(wa.annotations.getFeatures())\n-    for rec in GFF.parse(args.gff3):\n-        wa.annotations.setSequence(rec.id, org[\'id\'])\n-        for feature in rec.features:\n-            # We can only handle genes right now\n-            if feature.type not in (\'gene\', \'terminator\'):\n-                continue\n-            # Convert the feature into a presentation that Apollo will accept\n-            featureData = featuresToFeatureSchema([feature])\n-            if \'children\' in featureData[0] and any([child[\'type\'][\'name\'] == \'tRNA\' for child in featureData[0][\'children\']]):\n-                # We\'re experiencing a (transient?) problem where gene_001 to\n-                # gene_025 will be rejected. Thus, hardcode to a known working\n-                # gene name and update later.\n-\n-                featureData[0][\'name\'] = \'tRNA_000\'\n-                tRNA_sf = [child for child in feature.sub_features if child.type == \'tRNA\'][0]\n-                tRNA_type = \'tRNA-\' + tRNA_sf.qualifiers.get(\'Codon\', ["Unk"])[0]\n-\n-                if \'Name\' in feature.qualifiers:\n-                    if feature.qualifiers[\'Name\'][0].startswith(\'tRNA-\'):\n-                        tRNA_type = feature.qualifiers[\'Name\'][0]\n-\n-                newfeature = wa.annotations.addFeature(featureData, trustme=True)\n-\n-                def func0():\n-                    wa.annotations.setName(\n-                        newfeature[\'features\'][0][\'uniquename\'],\n-                        tRNA_type,\n-                    )\n-                retry(func0)\n-\n-                if args.source:\n-                    gene_id = newfeature[\'features\'][0][\'parent_id\']\n-\n-                    def setSource():\n-                        wa.annotations.addAttributes(gene_id, {\'DatasetSource\': [args.source]})\n-                    retry(setSource)\n-\n-                sys.stdout.write(\'\\t\'.join([\n-                    feature.id,\n-                    newfeature[\'features\'][0][\'uniquename\'],\n-                    \'success\',\n-                ]))\n-            elif featureData[0][\'type\'][\'name\'] == \'terminator\':\n-                # We\'re experiencing a (transient?) problem where gene_001 to\n-                # gene_025 will'..b'eature.id,\n-                    newfeature[\'features\'][0][\'uniquename\'],\n-                    \'success\',\n-                ]))\n-            else:\n-                try:\n-                    # We\'re experiencing a (transient?) problem where gene_001 to\n-                    # gene_025 will be rejected. Thus, hardcode to a known working\n-                    # gene name and update later.\n-                    featureData[0][\'name\'] = \'gene_000\'\n-                    # Extract CDS feature from the feature data, this will be used\n-                    # to set the CDS location correctly (apollo currently screwing\n-                    # this up (2.0.6))\n-                    CDS = featureData[0][\'children\'][0][\'children\']\n-                    CDS = [x for x in CDS if x[\'type\'][\'name\'] == \'CDS\'][0][\'location\']\n-                    # Create the new feature\n-                    newfeature = wa.annotations.addFeature(featureData, trustme=True)\n-                    # Extract the UUIDs that apollo returns to us\n-                    mrna_id = newfeature[\'features\'][0][\'uniquename\']\n-                    gene_id = newfeature[\'features\'][0][\'parent_id\']\n-                    # Sleep to give it time to actually persist the feature. Apollo\n-                    # is terrible about writing + immediately reading back written\n-                    # data.\n-                    time.sleep(1)\n-                    # Correct the translation start, but with strand specific log\n-                    if CDS[\'strand\'] == 1:\n-                        wa.annotations.setTranslationStart(mrna_id, min(CDS[\'fmin\'], CDS[\'fmax\']))\n-                    else:\n-                        wa.annotations.setTranslationStart(mrna_id, max(CDS[\'fmin\'], CDS[\'fmax\']) - 1)\n-\n-                    # Finally we set the name, this should be correct.\n-                    time.sleep(0.5)\n-                    wa.annotations.setName(mrna_id, feature.qualifiers.get(\'product\', feature.qualifiers.get(\'Name\', ["Unknown"]))[0])\n-                    time.sleep(0.5)\n-\n-                    def func():\n-                        wa.annotations.setName(gene_id, feature.qualifiers.get(\'product\', feature.qualifiers.get(\'Name\', ["Unknown"]))[0])\n-                    retry(func)\n+    orgs = accessible_organisms(gx_user, [org_cn], \'WRITE\')\n+    if not orgs:\n+        raise Exception("You do not have write permission on this organism")\n \n-                    if args.source:\n-                        gene_id = newfeature[\'features\'][0][\'parent_id\']\n-\n-                        def setSource():\n-                            wa.annotations.addAttributes(gene_id, {\'DatasetSource\': [args.source]})\n-                        retry(setSource)\n-                    extra_attr = {}\n-                    for (key, values) in feature.qualifiers.items():\n-                        if key in bad_quals:\n-                            continue\n-\n-                        if key == \'Note\':\n-                            def func2():\n-                                wa.annotations.addComments(gene_id, values)\n-                            retry(func2)\n-                        else:\n-                            extra_attr[key] = values\n-\n-                    def func3():\n-                        wa.annotations.addAttributes(gene_id, extra_attr)\n-                    retry(func3)\n-\n-                    sys.stdout.write(\'\\t\'.join([\n-                        feature.id,\n-                        gene_id,\n-                        \'success\',\n-                    ]))\n-                except Exception as e:\n-                    msg = str(e)\n-                    if \'\\n\' in msg:\n-                        msg = msg[0:msg.index(\'\\n\')]\n-                    sys.stdout.write(\'\\t\'.join([\n-                        feature.id,\n-                        \'\',\n-                        \'ERROR\',\n-                        msg\n-                    ]))\n-            sys.stdout.write(\'\\n\')\n-            sys.stdout.flush()\n+    wa.annotations.load_gff3(org_cn, args.gff3, args.source)\n'
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 create_or_update_organism.py
--- a/create_or_update_organism.py Mon Jul 29 10:09:19 2019 -0400
+++ b/create_or_update_organism.py Mon Dec 02 05:44:41 2019 -0500
[
b'@@ -2,17 +2,25 @@\n from __future__ import print_function\n \n import argparse\n+import glob\n import json\n import logging\n import os\n import shutil\n+import stat\n import subprocess\n import sys\n+import tarfile\n import tempfile\n import time\n \n+from apollo import accessible_organisms\n+from apollo.util import GuessOrg, OrgOrGuess\n \n-from webapollo import GuessOrg, OrgOrGuess, PermissionCheck, WAAuth, WebApolloInstance\n+from arrow.apollo import get_apollo_instance\n+\n+from webapollo import UserObj, handle_credentials\n+\n logging.basicConfig(level=logging.INFO)\n log = logging.getLogger(__name__)\n \n@@ -27,11 +35,24 @@\n         return False\n \n \n+def IsOrgCNSuffixEnabled():\n+    if \'GALAXY_APOLLO_ORG_SUFFIX\' not in os.environ:\n+        return False\n+    value = os.environ[\'GALAXY_APOLLO_ORG_SUFFIX\'].lower()\n+    if value in (\'id\', \'email\'):\n+        return value\n+\n+    return False\n+\n+\n+def IsRemote():\n+    return \'GALAXY_SHARED_DIR\' not in os.environ or len(os.environ[\'GALAXY_SHARED_DIR\'].lower().strip()) == 0\n+\n+\n if __name__ == \'__main__\':\n     parser = argparse.ArgumentParser(description=\'Create or update an organism in an Apollo instance\')\n-    WAAuth(parser)\n-    parser.add_argument(\'jbrowse_src\', help=\'Old JBrowse Data Directory\')\n-    parser.add_argument(\'jbrowse\', help=\'JBrowse Data Directory\')\n+    parser.add_argument(\'jbrowse_src\', help=\'Source JBrowse Data Directory\')\n+    parser.add_argument(\'jbrowse\', help=\'Destination JBrowse Data Directory\')\n     parser.add_argument(\'email\', help=\'User Email\')\n     OrgOrGuess(parser)\n     parser.add_argument(\'--genus\', help=\'Organism Genus\')\n@@ -39,94 +60,158 @@\n     parser.add_argument(\'--public\', action=\'store_true\', help=\'Make organism public\')\n     parser.add_argument(\'--group\', help=\'Give access to a user group\')\n     parser.add_argument(\'--remove_old_directory\', action=\'store_true\', help=\'Remove old directory\')\n+    parser.add_argument(\'--no_reload_sequences\', action=\'store_true\', help=\'Disable update genome sequence\')\n+    parser.add_argument(\'--userid\', help=\'User unique id\')\n     args = parser.parse_args()\n     CHUNK_SIZE = 2**20\n     blat_db = None\n \n+    path_fasta = args.jbrowse_src + \'/seq/genome.fasta\'\n+\n     # Cleanup if existing\n-    if(os.path.exists(args.jbrowse)):\n-        shutil.rmtree(args.jbrowse)\n-    # Copy files\n-    shutil.copytree(args.jbrowse_src, args.jbrowse, symlinks=True)\n+    if not IsRemote():\n+        if(os.path.exists(args.jbrowse)):\n+            shutil.rmtree(args.jbrowse)\n+        # Copy files\n+        shutil.copytree(args.jbrowse_src, args.jbrowse, symlinks=True)\n \n-    path_fasta = args.jbrowse + \'/seq/genome.fasta\'\n-    path_2bit = args.jbrowse + \'/seq/genome.2bit\'\n+        path_2bit = args.jbrowse + \'/seq/genome.2bit\'\n+    else:\n+        twobittemp = tempfile.NamedTemporaryFile(prefix="genome.2bit")\n+        path_2bit = twobittemp.name\n+        os.chmod(path_2bit, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)\n \n     # Convert fasta if existing\n-    if(IsBlatEnabled() and os.path.exists(path_fasta)):\n+    if IsBlatEnabled() and os.path.exists(path_fasta):\n         arg = [\'faToTwoBit\', path_fasta, path_2bit]\n-        tmp_stderr = tempfile.NamedTemporaryFile(prefix="tmp-twobit-converter-stderr")\n-        proc = subprocess.Popen(args=arg, shell=False, cwd=args.jbrowse, stderr=tmp_stderr.fileno())\n-        return_code = proc.wait()\n-        if return_code:\n-            tmp_stderr.flush()\n-            tmp_stderr.seek(0)\n+        proc = subprocess.Popen(args=arg, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n+        out, err = proc.communicate()\n+        if proc.returncode:\n             print("Error building index:", file=sys.stderr)\n-            while True:\n-                chunk = tmp_stderr.read(CHUNK_SIZE)\n-                if not chunk:\n-                    break\n-                sys.stderr.write(chunk)\n-            sys.exit(return_code)\n-        blat_db = path_2bit\n-        tmp_stderr.close()\n+            sys.stderr.write(er'..b'        blatdb=blat_db,\n+                    genus=args.genus,\n+                    species=args.species,\n+                    public=args.public,\n+                    no_reload_sequences=args.no_reload_sequences\n+                )\n+        else:\n+            data = wa.organisms.update_organism(\n+                org[\'id\'],\n+                org_cn,\n+                args.jbrowse,\n+                # mandatory\n+                genus=args.genus,\n+                species=args.species,\n+                public=args.public,\n+                blatdb=blat_db,\n+                no_reload_sequences=args.no_reload_sequences\n+            )\n         time.sleep(2)\n-        if args.remove_old_directory and args.jbrowse != old_directory:\n+\n+        if not IsRemote() and args.remove_old_directory and args.jbrowse != old_directory:\n             shutil.rmtree(old_directory)\n \n-        data = [wa.organisms.findOrganismById(org[\'id\'])]\n+        data = wa.organisms.show_organism(org_cn)\n \n     else:\n         # New organism\n         log.info("\\tAdding Organism")\n-        data = wa.organisms.addOrganism(\n-            org_cn,\n-            args.jbrowse,\n-            genus=args.genus,\n-            species=args.species,\n-            public=args.public,\n-            blatdb=blat_db\n-        )\n+\n+        if IsRemote():\n+            with tempfile.NamedTemporaryFile(suffix=\'.tar.gz\') as archive:\n+                with tarfile.open(archive.name, mode="w:gz") as tar:\n+                    dataset_data_dir = args.jbrowse_src\n+                    for file in glob.glob(dataset_data_dir):\n+                        tar.add(file, arcname=file.replace(dataset_data_dir, \'./\'))\n+                    if IsBlatEnabled():\n+                        with tempfile.TemporaryDirectory() as empty_dir:\n+                            os.chmod(empty_dir, stat.S_IRUSR | stat.S_IXUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)\n+                            tar.add(empty_dir, arcname="./searchDatabaseData/")\n+                            tar.add(path_2bit, arcname="./searchDatabaseData/genome.2bit")\n+                data = wa.remote.add_organism(\n+                    org_cn,\n+                    archive,\n+                    blatdb=blat_db,\n+                    genus=args.genus,\n+                    species=args.species,\n+                    public=args.public,\n+                    metadata=None\n+                )\n+                if isinstance(data, list) and len(data) > 0:\n+                    data = data[0]\n+        else:\n+            data = wa.organisms.add_organism(\n+                org_cn,\n+                args.jbrowse,\n+                blatdb=blat_db,\n+                genus=args.genus,\n+                species=args.species,\n+                public=args.public,\n+                metadata=None\n+            )\n \n         # Must sleep before we\'re ready to handle\n         time.sleep(2)\n         log.info("Updating permissions for %s on %s", gx_user, org_cn)\n-        wa.users.updateOrganismPermission(\n-            gx_user, org_cn,\n+        wa.users.update_organism_permissions(\n+            gx_user.username,\n+            org_cn,\n             write=True,\n             export=True,\n             read=True,\n@@ -134,10 +219,9 @@\n \n         # Group access\n         if args.group:\n-            group = wa.groups.loadGroupByName(name=args.group)\n-            res = wa.groups.updateOrganismPermission(group, org_cn,\n-                                                     administrate=False, write=True, read=True,\n-                                                     export=True)\n+            group = wa.groups.get_groups(name=args.group)[0]\n+            res = wa.groups.update_organism_permissions(group[\'name\'], org_cn,\n+                                                        administrate=False, write=True, read=True,\n+                                                        export=True)\n \n-    data = [o for o in data if o[\'commonName\'] == org_cn]\n     print(json.dumps(data, indent=2))\n'
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 delete_features.py
--- a/delete_features.py Mon Jul 29 10:09:19 2019 -0400
+++ b/delete_features.py Mon Dec 02 05:44:41 2019 -0500
[
@@ -5,40 +5,54 @@
 import logging
 import random
 
-from webapollo import GuessOrg, OrgOrGuess, PermissionCheck, WAAuth, WebApolloInstance, retry
+from apollo import accessible_organisms
+from apollo.util import GuessOrg, OrgOrGuess, retry
+
+from arrow.apollo import get_apollo_instance
+
+from webapollo import UserObj, handle_credentials
+
 logging.basicConfig(level=logging.INFO)
 log = logging.getLogger(__name__)
 
 
 if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Sample script to delete all features from an organism')
-    WAAuth(parser)
+    parser = argparse.ArgumentParser(description='Script to delete all features from an organism')
     parser.add_argument('email', help='User Email')
     parser.add_argument('--type', help='Feature type filter')
     OrgOrGuess(parser)
 
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
+    wa = get_apollo_instance()
     # User must have an account
-    gx_user = wa.users.assertOrCreateUser(args.email)
+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))
+    handle_credentials(gx_user)
 
     # Get organism
     org_cn = GuessOrg(args, wa)
     if isinstance(org_cn, list):
         org_cn = org_cn[0]
 
-    if not PermissionCheck(gx_user, org_cn, "WRITE"):
-        raise Exception("Action not permitted")
-    org = wa.organisms.findOrganismByCn(org_cn)
+    all_orgs = wa.organisms.get_organisms()
+    if 'error' in all_orgs:
+        all_orgs = []
+    all_orgs = [org['commonName'] for org in all_orgs]
+    if org_cn not in all_orgs:
+        raise Exception("Could not find organism %s" % org_cn)
 
-    sequences = wa.organisms.getSequencesForOrganism(org['id'])
+    orgs = accessible_organisms(gx_user, [org_cn], 'WRITE')
+    if not orgs:
+        raise Exception("You do not have write permission on this organism")
+    org = wa.organisms.show_organism(org_cn)
+
+    sequences = wa.organisms.get_sequences(org['id'])
     for sequence in sequences['sequences']:
         log.info("Processing %s %s", org['commonName'], sequence['name'])
         # Call setSequence to tell apollo which organism we're working with
-        wa.annotations.setSequence(sequence['name'], org['id'])
+        wa.annotations.set_sequence(org['id'], sequence['name'])
         # Then get a list of features.
-        features = wa.annotations.getFeatures()
+        features = wa.annotations.get_features()
         # For each feature in the features
         for feature in sorted(features['features'], key=lambda x: random.random()):
             if args.type:
@@ -60,7 +74,7 @@
             # We see that deleteFeatures wants a uniqueName, and so we pass
             # is the uniquename field in the feature.
             def fn():
-                wa.annotations.deleteFeatures([feature['uniquename']])
+                wa.annotations.delete_feature(feature['uniquename'])
                 print('Deleted %s [type=%s]' % (feature['uniquename'], feature['type']['name']))
 
             if not retry(fn, limit=3):
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 delete_features.xml
--- a/delete_features.xml Mon Jul 29 10:09:19 2019 -0400
+++ b/delete_features.xml Mon Dec 02 05:44:41 2019 -0500
[
@@ -7,29 +7,32 @@
   <expand macro="requirements"/>
   <code file="webapollo.py"/>
   <command detect_errors="aggressive"><![CDATA[
+@AUTH@
+
 #if str($ask_one) == "yes":
  ## Nope, still don't trust them to not be dumb (or malicious), so we backup first.
- python $__tool_directory__/export.py
- @ADMIN_AUTH@
+ python '$__tool_directory__/export.py'
  @ORG_OR_GUESS@
- --gff "$gff_out"
- --fasta "$fasta_out"
- --json "$json_out"
-    "$__user_email__"
+ --gff '$gff_out'
+        --fasta_pep '$fasta_pep'
+        --fasta_cds '$fasta_cds'
+        --fasta_cdna '$fasta_cdna'
+        --vcf '$vcf_out'
+ --json '$json_out'
+  '$__user_email__'
 
     &&
 
  ## Now we delete
- python $__tool_directory__/delete_features.py
- @ADMIN_AUTH@
+ python '$__tool_directory__/delete_features.py'
  @ORG_OR_GUESS@
- "$__user_email__"
+ '$__user_email__'
  #if str($filter) != "all"
  --type $filter
  #end if
- > $output;
+ > '$output';
 #else
-    echo "Nothing to do" > $output;
+    echo "Nothing to do" > '$output';
 #end if
     ]]></command>
   <inputs>
@@ -43,23 +46,49 @@
     <param name="ask_one" type="boolean" truevalue="yes" falsevalue="" label="Are you SURE you want to do this?" help="It will PERMANENTLY delete all of the features on this organism."/>
   </inputs>
   <outputs>
-    <data format="tabular" name="output" label="Process and Error Log">
+    <data format="txt" name="output" label="Process and Error Log">
         <discover_datasets pattern="(?P&lt;designation&gt;.+)\.txt" format="tabular" visible="true"/>
     </data>
 
-    <data format="gff3" name="gff_out" label="Annotations from Apollo" hidden="true"/>
-    <data format="fasta" name="fasta_out" label="Sequence(s) from Apollo" hidden="true"/>
-    <data format="json" name="json_out" label="Metadata from Apollo" hidden="true"/>
+    <data format="gff3" name="gff_out" label="Annotations from Apollo"/>
+    <data format="fasta" name="fasta_pep" label="Peptide sequences from Apollo"/>
+    <data format="fasta" name="fasta_cds" label="CDS sequences from Apollo"/>
+    <data format="fasta" name="fasta_cdna" label="cDNA sequences from Apollo"/>
+    <data format="vcf" name="vcf_out" label="Sequence alterations from Apollo"/>
+    <data format="json" name="json_out" label="Metadata from Apollo"/>
   </outputs>
   <tests>
-      <test expect_failure="true">
+      <test>
           <conditional name="org_source">
               <param name="source_select" value="direct"/>
-              <param name="org_raw" value="Test org" />
+              <param name="org_raw" value="org4" />
           </conditional>
           <param name="filter" value="all"/>
           <param name="ask_one" value="yes"/>
-          <expand macro="test_result" />
+
+          <output name="gff_out">
+              <assert_contents>
+                  <has_text text="##sequence-region Merlin 1 172788" />
+                  <has_text text="owner=admin@local.host;" />
+                  <has_text text="Name=cds-not-under-exon" />
+              </assert_contents>
+          </output>
+          <output name="fasta_pep" file="export/pep.fa" lines_diff="12"/>
+          <output name="fasta_cds" file="export/cds.fa" lines_diff="12"/>
+          <output name="fasta_cdna" file="export/cdna.fa" lines_diff="12"/>
+          <output name="vcf_out" file="export/out.vcf" lines_diff="4"/>
+          <output name="json_out">
+              <assert_contents>
+                  <has_text text="org4" />
+                  <has_text text="apollo_shared_dir/org4" />
+              </assert_contents>
+          </output>
+          <output name="output">
+              <assert_contents>
+                  <has_text text="Deleted" />
+                  <has_text text="[type=mRNA]" />
+              </assert_contents>
+          </output>
       </test>
   </tests>
   <help><![CDATA[
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 delete_organism.py
--- a/delete_organism.py Mon Jul 29 10:09:19 2019 -0400
+++ b/delete_organism.py Mon Dec 02 05:44:41 2019 -0500
[
@@ -3,41 +3,56 @@
 
 import argparse
 import logging
+import os
 
-from webapollo import GuessOrg, OrgOrGuess, PermissionCheck, WAAuth, WebApolloInstance
+from apollo import accessible_organisms
+from apollo.util import GuessOrg, OrgOrGuess
+
+from arrow.apollo import get_apollo_instance
+
+from webapollo import UserObj, handle_credentials
+
 logging.basicConfig(level=logging.INFO)
 log = logging.getLogger(__name__)
 
 
+def IsRemote():
+    return 'GALAXY_SHARED_DIR' not in os.environ or len(os.environ['GALAXY_SHARED_DIR'].lower().strip()) == 0
+
+
 if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Sample script to completely delete an organism')
-    WAAuth(parser)
+    parser = argparse.ArgumentParser(description='Script to completely delete an organism')
     parser.add_argument('email', help='User Email')
     OrgOrGuess(parser)
 
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
+    wa = get_apollo_instance()
+
     # User must have an account
-    gx_user = wa.users.assertOrCreateUser(args.email)
+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))
+    handle_credentials(gx_user)
 
     # Get organism
     org_cn = GuessOrg(args, wa)
     if isinstance(org_cn, list):
         org_cn = org_cn[0]
 
-    if not PermissionCheck(gx_user, org_cn, "WRITE"):
-        raise Exception("You do not have write permission on this organism")
-    org = wa.organisms.findOrganismByCn(org_cn)
+    all_orgs = wa.organisms.get_organisms()
+    if 'error' in all_orgs:
+        all_orgs = []
+    all_orgs = [org['commonName'] for org in all_orgs]
+    if org_cn not in all_orgs:
+        raise Exception("Could not find organism %s" % org_cn)
 
-    # Call setSequence to tell apollo which organism we're working with
-    wa.annotations.setSequence(org['commonName'], org['id'])
-    # Then get a list of features.
-    features = wa.annotations.getFeatures()
-    # For each feature in the features
-    # If it exists
-    if 'features' in features:
-        for feature in features['features']:
-            # We see that deleteFeatures wants a uniqueName, and so we pass
-            # is the uniquename field in the feature.
-            print(wa.annotations.deleteFeatures([feature['uniquename']]))
+    orgs = accessible_organisms(gx_user, [org_cn], 'WRITE')
+    if not orgs:
+        raise Exception("You do not have write permission on this organism")
+    org = wa.organisms.show_organism(org_cn)
+
+    wa.organisms.delete_features(org['id'])
+
+    if IsRemote():
+        print(wa.remote.delete_organism(org['commonName']))
+    else:
+        print(wa.organisms.delete_organism(org['id']))
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 export.py
--- a/export.py Mon Jul 29 10:09:19 2019 -0400
+++ b/export.py Mon Dec 02 05:44:41 2019 -0500
[
@@ -3,89 +3,86 @@
 
 import argparse
 import json
-import sys
-
-from BCBio import GFF
-
-from Bio import SeqIO
-
-from webapollo import CnOrGuess, GuessCn, PermissionCheck, WAAuth, WebApolloInstance
-
-try:
-    import StringIO as io
-except ImportError:
-    import io
-
-
-def export(org_cn, seqs):
-    org_data = wa.organisms.findOrganismByCn(org_cn)
-
-    data = io.StringIO()
-
-    kwargs = dict(
-        exportType='GFF3',
-        seqType='genomic',
-        exportGff3Fasta=True,
-        output="text",
-        exportFormat="text",
-        organism=org_cn,
-    )
+import time
 
-    if len(seqs) > 0:
-        data.write(wa.io.write(
-            exportAllSequences=False,
-            sequences=seqs,
-            **kwargs
-        ).encode('utf-8'))
-    else:
-        data.write(wa.io.write(
-            exportAllSequences=True,
-            sequences=[],
-            **kwargs
-        ).encode('utf-8'))
-
-    # Seek back to start
-    data.seek(0)
+from apollo import accessible_organisms
+from apollo.util import CnOrGuess, GuessCn
 
-    records = list(GFF.parse(data))
-    if len(records) == 0:
-        print("Could not find any sequences or annotations for this organism + reference sequence")
-        sys.exit(2)
-    else:
-        for record in records:
-            record.annotations = {}
-            record.features = sorted(record.features, key=lambda x: x.location.start)
-            if args.gff:
-                GFF.write([record], args.gff)
-            record.description = ""
-            if args.fasta:
-                SeqIO.write([record], args.fasta, 'fasta')
+from arrow.apollo import get_apollo_instance
 
-    return org_data
-
+from webapollo import UserObj, handle_credentials
 
 if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description='Sample script to add an attribute to a feature via web services')
-    WAAuth(parser)
+    parser = argparse.ArgumentParser(description='Script to export data from Apollo via web services')
     CnOrGuess(parser)
     parser.add_argument('--gff', type=argparse.FileType('w'))
-    parser.add_argument('--fasta', type=argparse.FileType('w'))
+    parser.add_argument('--fasta_pep', type=argparse.FileType('w'))
+    parser.add_argument('--fasta_cds', type=argparse.FileType('w'))
+    parser.add_argument('--fasta_cdna', type=argparse.FileType('w'))
+    parser.add_argument('--vcf', type=argparse.FileType('w'))
     parser.add_argument('--json', type=argparse.FileType('w'))
     parser.add_argument('email', help='User Email')
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
-
-    org_cn_list, seqs = GuessCn(args, wa)
+    wa = get_apollo_instance()
 
     # User must have an apollo account, if not, create it
-    gx_user = wa.users.assertOrCreateUser(args.email)
+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))
+    handle_credentials(gx_user)
+
+    org_cns, seqs = GuessCn(args, wa)
+    if not isinstance(org_cns, list):
+        org_cns = [org_cns]
+
+    all_orgs = wa.organisms.get_organisms()
+    if 'error' in all_orgs:
+        all_orgs = []
+    all_orgs = [org['commonName'] for org in all_orgs]
 
     org_data = []
-    for org_cn in org_cn_list:
-        # User must have read permission on organism
-        if not PermissionCheck(gx_user, org_cn, "READ"):
-            continue
-        indiv_org_data = export(org_cn, seqs)
-        org_data.append(indiv_org_data)
+    for org_cn in org_cns:
+        if org_cn not in all_orgs:
+            raise Exception("Could not find organism %s" % org_cn)
+
+        orgs = accessible_organisms(gx_user, [org_cn], 'READ')
+        if not orgs:
+            raise Exception("You do not have read permission on organism %s" % org_cn)
+
+        org = wa.organisms.show_organism(org_cn)
+
+        uuid_gff = wa.io.write_downloadable(org['commonName'], 'GFF3', export_gff3_fasta=True, sequences=seqs)
+        if 'error' in uuid_gff or 'uuid' not in uuid_gff:
+            raise Exception("Apollo failed to prepare the file for download: %s" % uuid_gff)
+        args.gff.write(wa.io.download(uuid_gff['uuid'], output_format="text"))
+
+        time.sleep(1)
+
+        uuid_vcf = wa.io.write_downloadable(org['commonName'], 'VCF', sequences=seqs)
+        if 'error' in uuid_vcf or 'uuid' not in uuid_vcf:
+            raise Exception("Apollo failed to prepare the file for download: %s" % uuid_vcf)
+        args.vcf.write(wa.io.download(uuid_vcf['uuid'], output_format="text"))
+
+        time.sleep(1)
+
+        uuid_fa = wa.io.write_downloadable(org['commonName'], 'FASTA', sequences=seqs, seq_type='cdna')
+        if 'error' in uuid_fa or 'uuid' not in uuid_fa:
+            raise Exception("Apollo failed to prepare the file for download: %s" % uuid_fa)
+        args.fasta_cdna.write(wa.io.download(uuid_fa['uuid'], output_format="text"))
+
+        time.sleep(1)
+
+        uuid_fa = wa.io.write_downloadable(org['commonName'], 'FASTA', sequences=seqs, seq_type='cds')
+        if 'error' in uuid_fa or 'uuid' not in uuid_fa:
+            raise Exception("Apollo failed to prepare the file for download: %s" % uuid_fa)
+        args.fasta_cds.write(wa.io.download(uuid_fa['uuid'], output_format="text"))
+
+        time.sleep(1)
+
+        uuid_fa = wa.io.write_downloadable(org['commonName'], 'FASTA', sequences=seqs, seq_type='peptide')
+        if 'error' in uuid_fa or 'uuid' not in uuid_fa:
+            raise Exception("Apollo failed to prepare the file for download: %s" % uuid_fa)
+        args.fasta_pep.write(wa.io.download(uuid_fa['uuid'], output_format="text"))
+
+        org_data.append(org)
+
     args.json.write(json.dumps(org_data, indent=2))
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 fetch_organism_jbrowse.py
--- a/fetch_organism_jbrowse.py Mon Jul 29 10:09:19 2019 -0400
+++ b/fetch_organism_jbrowse.py Mon Dec 02 05:44:41 2019 -0500
[
@@ -9,7 +9,13 @@
 import sys
 import time
 
-from webapollo import GuessOrg, OrgOrGuess, PermissionCheck, WAAuth, WebApolloInstance
+from apollo import accessible_organisms
+from apollo.util import GuessOrg, OrgOrGuess
+
+from arrow.apollo import get_apollo_instance
+
+from webapollo import UserObj, handle_credentials
+
 logging.basicConfig(level=logging.INFO)
 log = logging.getLogger(__name__)
 
@@ -52,27 +58,34 @@
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='Sample script to add an attribute to a feature via web services')
-    WAAuth(parser)
     OrgOrGuess(parser)
     parser.add_argument('target_dir', help='Target directory')
     parser.add_argument('email', help='User Email')
 
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
+    wa = get_apollo_instance()
     # User must have an account
     org_cn = GuessOrg(args, wa)
     if isinstance(org_cn, list):
         org_cn = org_cn[0]
-    org = wa.organisms.findOrganismByCn(org_cn)
 
     # User must have an account, if not, create it
-    gx_user = wa.users.assertOrCreateUser(args.email)
+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))
+    handle_credentials(gx_user)
+
+    all_orgs = wa.organisms.get_organisms()
+    if 'error' in all_orgs:
+        all_orgs = []
+    all_orgs = [org['commonName'] for org in all_orgs]
+    if org_cn not in all_orgs:
+        raise Exception("Could not find organism %s" % org_cn)
 
     # User must have READ access
-
-    if not PermissionCheck(gx_user, org_cn, "READ"):
-        raise Exception("READ permissions are required for this action")
+    orgs = accessible_organisms(gx_user, [org_cn], 'READ')
+    if not orgs:
+        raise Exception("You do not have write permission on this organism")
+    org = wa.organisms.show_organism(org_cn)
 
     if not os.path.exists(args.target_dir):
         os.makedirs(args.target_dir)
@@ -94,7 +107,7 @@
     # files / folders before and after.
     sys.stderr.write(' '.join(cmd))
     sys.stderr.write('\n')
-    sys.stderr.write(subprocess.check_output(cmd))
+    sys.stderr.write(subprocess.check_output(cmd).decode(sys.stderr.encoding))
     if not are_dir_trees_equal(
         os.path.join(org['directory'].rstrip('/')),
         os.path.join(args.target_dir, 'data')
@@ -104,7 +117,7 @@
         sys.stderr.write('\n')
         sys.stderr.write(' '.join(cmd))
         sys.stderr.write('\n')
-        sys.stderr.write(subprocess.check_output(cmd))
+        sys.stderr.write(subprocess.check_output(cmd).decode(sys.stderr.encoding))
         if not are_dir_trees_equal(
             os.path.join(org['directory'].rstrip('/'), 'data'),
             os.path.join(args.target_dir, 'data')
@@ -113,7 +126,7 @@
             sys.stderr.write('\n')
             sys.stderr.write(' '.join(cmd))
             sys.stderr.write('\n')
-            sys.stderr.write(subprocess.check_output(cmd))
+            sys.stderr.write(subprocess.check_output(cmd).decode(sys.stderr.encoding))
             if not are_dir_trees_equal(
                 os.path.join(org['directory'].rstrip('/'), 'data'),
                 os.path.join(args.target_dir, 'data')
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 list_organisms.py
--- a/list_organisms.py Mon Jul 29 10:09:19 2019 -0400
+++ b/list_organisms.py Mon Dec 02 05:44:41 2019 -0500
b
@@ -4,19 +4,23 @@
 import argparse
 import json
 
-from webapollo import WAAuth, WebApolloInstance, accessible_organisms
+from apollo import accessible_organisms
+
+from arrow.apollo import get_apollo_instance
+
+from webapollo import UserObj, handle_credentials
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='List all organisms available in an Apollo instance')
-    WAAuth(parser)
     parser.add_argument('email', help='User Email')
     args = parser.parse_args()
 
-    wa = WebApolloInstance(args.apollo, args.username, args.password)
+    wa = get_apollo_instance()
 
-    gx_user = wa.users.assertOrCreateUser(args.email)
+    gx_user = UserObj(**wa.users._assert_or_create_user(args.email))
+    handle_credentials(gx_user)
 
-    all_orgs = wa.organisms.findAllOrganisms()
+    all_orgs = wa.organisms.get_organisms()
 
     orgs = accessible_organisms(gx_user, all_orgs)
 
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 macros.xml
--- a/macros.xml Mon Jul 29 10:09:19 2019 -0400
+++ b/macros.xml Mon Dec 02 05:44:41 2019 -0500
[
@@ -1,14 +1,10 @@
 <?xml version="1.0"?>
 <macros>
-  <token name="@WRAPPER_VERSION@">4.0.0</token>
+  <token name="@WRAPPER_VERSION@">4.1</token>
 
   <xml name="requirements">
     <requirements>
-      <requirement type="package" version="2.7">python</requirement>
-      <requirement type="package" version="1.65">biopython</requirement>
-      <requirement type="package" version="0.6.2">bcbiogff</requirement>
-      <requirement type="package" version="2.12.4">requests</requirement>
-      <requirement type="package" version="1.11.0">six</requirement>
+      <requirement type="package" version="4.1">apollo</requirement>
       <yield/>
     </requirements>
   </xml>
@@ -19,20 +15,27 @@
   <token name="@URL@">
 "\$GALAXY_WEBAPOLLO_URL"
   </token>
-  <token name="@ADMIN_AUTH@">
-"\$GALAXY_WEBAPOLLO_URL"
-"\$GALAXY_WEBAPOLLO_USER"
-"\$GALAXY_WEBAPOLLO_PASSWORD"
-  </token>
+
+  <token name="@AUTH@"><![CDATA[
+      if [ -z "\$ARROW_GLOBAL_CONFIG_PATH" ]; then
+        echo "__default: local" > '.auth.yml' &&
+        echo "local:" >> '.auth.yml' &&
+        echo "    url: \"\$GALAXY_WEBAPOLLO_URL\"" >> '.auth.yml' &&
+        echo "    username: \"\$GALAXY_WEBAPOLLO_USER\"" >> '.auth.yml' &&
+        echo "    password: \"\$GALAXY_WEBAPOLLO_PASSWORD\"" >> '.auth.yml' &&
+
+        export ARROW_GLOBAL_CONFIG_PATH='.auth.yml'
+      ; fi &&
+  ]]></token>
 
   <token name="@ORG_OR_GUESS@">
 <![CDATA[
 #if $org_source.source_select == "auto_json":
-    --org_json "${org_source.org_file}"
+    --org_json '${org_source.org_file}'
 #elif $org_source.source_select == "select":
-    --org_id "${org_source.org_select}"
+    --org_id '${org_source.org_select}'
 #else:
-    --org_raw "${org_source.org_raw}"
+    --org_raw '${org_source.org_raw}'
 #end if
 ]]>
   </token>
@@ -42,13 +45,13 @@
 
 #if $cn_source.source_select == "auto":
     #if str($cn_source.cn_file) != "None":
-        --seq_fasta $cn_source.cn_file
+        --seq_fasta '$cn_source.cn_file'
     #end if
 #else
     #if $cn_source.source_select != "all" and len($cn_source.refseqs) > 0:
         --seq_raw
         #for $item in $cn_source.refseqs:
-            "${item.refseq}"
+            '${item.refseq}'
         #end for
     #end if
 #end if
@@ -93,12 +96,6 @@
     </conditional>
   </xml>
 
-  <xml name="test_result">
-      <assert_stderr>
-          <has_text text="MissingSchema" />
-      </assert_stderr>
-  </xml>
-
   <xml name="citations">
       <citations>
         <citation type="doi">10.1371/journal.pcbi.1006790</citation>
@@ -109,12 +106,12 @@
   </xml>
   <token name="@GENOME_SELECTOR_PRE@">
 #if $reference_genome.reference_genome_source == 'history':
-    ln -s $reference_genome.genome_fasta genomeref.fa;
+    ln -s '$reference_genome.genome_fasta' genomeref.fa;
 #end if
   </token>
   <token name="@GENOME_SELECTOR@">
 #if $reference_genome.reference_genome_source == 'cached':
-    "${reference_genome.fasta_indexes.fields.path}"
+    '${reference_genome.fasta_indexes.fields.path}'
 #elif $reference_genome.reference_genome_source == 'history':
     genomeref.fa
 #end if
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/arrow.yml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/arrow.yml Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,5 @@
+__default: local
+local:
+    url: "http://localhost:8888"
+    username: "admin@local.host"
+    password: "password"
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/bad-model.gff3
--- a/test-data/bad-model.gff3 Mon Jul 29 10:09:19 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
b
@@ -1,9 +0,0 @@
-##gff-version 3
-##sequence-region Maroon_JMcDermott 1 144762
-Maroon_JMcDermott . gene 14488 14805 . + . Name=gene_26;date_creation=2016-02-17;owner=jmc_texas@tamu.edu;ID=707c88b7-36d1-44e3-93e6-d1d4f1219d57;date_last_modified=2016-02-17
-Maroon_JMcDermott . mRNA 14488 14805 . + . Name=gene_26-00001;date_creation=2016-02-17;Parent=707c88b7-36d1-44e3-93e6-d1d4f1219d57;owner=jmc_texas@tamu.edu;ID=8760695d-b88c-41c0-857b-540e6db81fe8;date_last_modified=2016-02-17
-Maroon_JMcDermott . CDS 14707 14805 . + 0 Name=94abf796-4c8d-45f4-916b-4d279616565e-CDS;Parent=8760695d-b88c-41c0-857b-540e6db81fe8;ID=94abf796-4c8d-45f4-916b-4d279616565e
-Maroon_JMcDermott . exon 14497 14805 . + . Name=d2ebd8d0-6558-4674-a38f-346f88256340-exon;Parent=8760695d-b88c-41c0-857b-540e6db81fe8;ID=d2ebd8d0-6558-4674-a38f-346f88256340
-Maroon_JMcDermott . exon 14488 14491 . + . Name=2e4119f9-3220-4502-8ddd-4821c872e0d6-exon;Parent=8760695d-b88c-41c0-857b-540e6db81fe8;ID=2e4119f9-3220-4502-8ddd-4821c872e0d6
-Maroon_JMcDermott . non_canonical_five_prime_splice_site 14494 14494 . + . Name=8760695d-b88c-41c0-857b-540e6db81fe8-non_canonical_five_prime_splice_site-14493;Parent=8760695d-b88c-41c0-857b-540e6db81fe8;ID=8760695d-b88c-41c0-857b-540e6db81fe8-non_canonical_five_prime_splice_site-14493
-Maroon_JMcDermott . non_canonical_three_prime_splice_site 14497 14497 . + . Name=8760695d-b88c-41c0-857b-540e6db81fe8-non_canonical_three_prive_splice_site-14496;Parent=8760695d-b88c-41c0-857b-540e6db81fe8;ID=8760695d-b88c-41c0-857b-540e6db81fe8-non_canonical_three_prive_splice_site-14496
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/create_org/output.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/create_org/output.json Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,16 @@
+{
+  "commonName": "Test org",
+  "blatdb": "/data/temporary/apollo_data/1384-Test_org/searchDatabaseData/genome.2bit",
+  "metadata": "{\"creator\":\"20\"}",
+  "annotationCount": 0,
+  "currentOrganism": true,
+  "obsolete": false,
+  "sequences": 1,
+  "directory": "/XX/apollo_shared_dir/1",
+  "publicMode": false,
+  "valid": true,
+  "genus": "genus",
+  "species": null,
+  "id": 23,
+  "nonDefaultTranslationTable": null
+}
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/create_org/output2.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/create_org/output2.json Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,16 @@
+{
+  "commonName": "Test org",
+  "blatdb": "/data/temporary/apollo_data/1384-Test_org/searchDatabaseData/genome.2bit",
+  "metadata": "{\"creator\":\"20\"}",
+  "annotationCount": 0,
+  "currentOrganism": true,
+  "obsolete": false,
+  "sequences": 1,
+  "directory": "/XX/apollo_shared_dir/3",
+  "publicMode": false,
+  "valid": true,
+  "genus": "genus2",
+  "species": "sp",
+  "id": 23,
+  "nonDefaultTranslationTable": null
+}
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1.dat
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1.dat Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <title>JBrowse</title>
+
+    <link rel="apple-touch-icon" sizes="180x180" href="img/favicons/apple-touch-icon.png">
+    <link rel="icon" type="image/png" sizes="32x32" href="img/favicons/favicon-32x32.png">
+    <link rel="icon" type="image/png" sizes="16x16" href="img/favicons/favicon-16x16.png">
+    <link rel="manifest" href="site.webmanifest">
+    <link rel="mask-icon" href="img/favicons/safari-pinned-tab.svg" color="#5bbad5">
+    <meta name="msapplication-TileColor" content="#2d89ef">
+    <meta name="theme-color" content="#ffffff">
+
+    <script type="text/javascript">
+        window.onerror=function(msg){
+            if( document.body )
+                document.body.setAttribute("JSError",msg);
+        }
+        if(window.process&&process.versions&&process.versions.electron) {
+            window.electronRequire = require;
+            delete window.require;
+        }
+    </script>
+    <style>
+        html, body, div.jbrowse {
+            margin: 0;
+            padding: 0;
+            height: 100%;
+            width: 100%;
+        }
+    </style>
+    <script type="text/javascript" src="dist/main.bundle.js" charset="utf-8"></script>
+  </head>
+
+  <body>
+    <div class="jbrowse" id="GenomeBrowser" data-config='"allowCrossOriginDataRoot": false, "cacheBuster": true'>
+      <div id="LoadingScreen" style="padding: 50px;">
+        <h1>Loading...</h1>
+      </div>
+    </div>
+    <div style="display: none">JBrowseDefaultMainPage</div>
+  </body>
+</html>
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/.htaccess
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/.htaccess Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,10 @@
+# This Apache .htaccess file is generated by JBrowse (GenomeDB) for
+# allowing cross-origin requests as defined by the Cross-Origin
+# Resource Sharing working draft from the W3C
+# (http://www.w3.org/TR/cors/).  In order for Apache to pay attention
+# to this, it must have mod_headers enabled, and its AllowOverride
+# configuration directive must allow FileInfo overrides.
+<IfModule mod_headers.c>
+    Header onsuccess set Access-Control-Allow-Origin *
+    Header onsuccess set Access-Control-Allow-Headers X-Requested-With,Range
+</IfModule>
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/02b/9.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/02b/9.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"merli":{"exact":[],"prefix":["Merlin"]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/0e9/3.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/0e9/3.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"mer":{"prefix":["Merlin"],"exact":[]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/83f/8.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/83f/8.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"merlin":{"prefix":[],"exact":[["Merlin",null,"Merlin",null,0,172788,null]]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/92c/2.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/92c/2.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"me":{"prefix":["Merlin"],"exact":[]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/cf0/e.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/cf0/e.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"merl":{"prefix":["Merlin"],"exact":[]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/f26/8.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/f26/8.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"m":{"exact":[],"prefix":["Merlin"]}}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/names/meta.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/names/meta.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+{"compress":0,"track_names":[],"format":"json","lowercase_keys":1,"hash_bits":16}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz
b
Binary file test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz has changed
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz.tbi
b
Binary file test-data/dataset_1_files/data/raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz.tbi has changed
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/seq/genome.fasta
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/seq/genome.fasta Mon Dec 02 05:44:41 2019 -0500
b
b'@@ -0,0 +1,2881 @@\n+>Merlin\n+TCGTTTAGACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACATTCGA\n+GCATAACGCAGAGAATAAGTTGTTCTATTTCAGAAACTACGTTTCAACTTCATTAAAGCC\n+TCTGATCTTTGGTGAATTTGGTCGTATGTTTATGGCACTAGATGACGATACTACAATTTA\n+TACTGCTGAGACGCCTGATGATTATAATCGTTTCGCAAACCCAGAAGATATAATTGATAT\n+TGGCGCTACTCAAAAAGACTCATTTGACGATAACAATAATGATGGAACATCTATTAATAT\n+CGGCAAACAAGTTAATTTAGGATTCGTTATTTCCGGTGCTGAAAATGTTCGAGTTATTGT\n+TCCAGGTTCTTTAACTGAATATCCAGAAGAAGCGGAAGTTATTCTGCCTCGTGGTACTCT\n+TTTGAAGATCAATAAAATCACTACTCAAGTAGATAAACGCTCGAATAAGTTCATGGTTGA\n+AGGTTCAATCGTTCCGCCTTCTGAGCAAATTGATGAATCTGTTGAGATTTATGACGGTGA\n+TCTGTTCATGGAAACAGGTGAAGTAGTAAAACTGTCCGGATTCATGCAGTTCGTCAACGA\n+ATCTGCATACGATGAAGAGCAAAACCAGATGGCTGCTGAGATTCTGTCTGGATTCTTGGA\n+CATTGATGACATGCCACGTAAGTTCCGCTAGCCGTTTACATCCACATGGAAGTGGATTAT\n+AATGGCTCTACGTTAACAAGAGGAAAACAACATGAAATCAATTTTTCGTATCAACGGTGT\n+AGAAATTGTAGTTGAAGATGTAGTTCCTATGTCTTATGAATTCAATGAAGTTGTTTTCAA\n+AGAGCTTAAGAAAATTTTAGGCGATAAGAAGCTTCAAAGTACTCCAATTGGACGTTTTGG\n+AATGAAAGAAAACGTTGATACTTATATTGAAAGTGTAGTGACAGGGCAGTTAGAAGGTGA\n+ATTTTCTGTAGCAGTTCAAACTGTAGAAAATGATGAAGTTATTTTAACTTTACCAGCTTT\n+CGTAATTTTCCGCAAATAAAACAATGGGGAGCTATGCTCCCCATTTTTACAATCCAAGTA\n+TTTTCGAAGTAGAGTTTCGGGTCGAATTAATGACGTGAGACAACCCTCCAGCAGCTCCTC\n+CAAGTCTAGATAATCTACTTAAACTTCCATTAAGAGACATTTCACTATTAATTCCAGTTA\n+TAGAATTAACAGCTCTATCTTCAATCCAATCAAGAGCAGCTTGACGTCCAACAGCACCCG\n+TTTGCATTACTCTGTAAGCAAATGTAACATCGAAAACCGCAATTTGGTTATCTCCTTCAT\n+ATGTAAGCTCAGGAGCTCCACACGCAACAGGAACACAACCTGTGAACATTATCACAGTAT\n+GAGGTAATCCATTTCGAGCATGAAGGTTAACCTGAATGTCAGCTTCGACGTCAGTTGGTA\n+ATGCTCGCAATCCAGTAACCGGGTCTTGAACGGAGTTCACCCAATCTTGCATTGCACGAT\n+AGTTACTTGCTTCGGGATCCATTCTGAATGATATAGTTAACGGATCGAGTTCACGTCCAG\n+TTATTCTAATATTCGGTGAGTTATGGTTGAAATCCATTTCATGAGACAATCTGTTCTCTG\n+GAATTTTGACCGAATAAATCATCAATCCAGATTGCGGATAAGCCATGTTAAAGAAGTCTA\n+ACAAATAAGTTCCGACTTCAAATTCACCTAATAAAGACTGAACAACACGATTGCTCATTG\n+CTCCAATAAGATATTTCGATACACCAGACTTTCTTACCAGCTGTTGAGTACCGGCAGTGA\n+TAATTGAGGTGAGTCCTGATGTGAACTCACCTTGTGTTAATCCAAGCCAGTCATTATTCA\n+ACGGAAGGTTATTAAAGAGCATACCGCCAAATTGATCGAGTAATTGTTGAGACTTTGCTG\n+ACGGAGTAGTTGCAAATACACAACTAAACATATTAGTACGCTGAAAGTCTATATTACCCG\n+CTTGGTTTTTAAATTCATCTAAAGTTAGCATCAGAATCCTTCCGCATATACTGAAGCTCG\n+GTTCAATGTCAAGATTTCACGCATAGTAATTTCTAATGTGAATGTACTTGGCAGGTTTGG\n+AGCTATAGCTAAACCGTTAAAGTTTCCATTTGGAGTTTTATCAAAACGGATACTCTGAAT\n+TTGACATGGACCGAATACTTCAGCACGTCCATCGAATTTACTTGTGGTTCCAAAGTTTCT\n+GACGAACCACACAGTAGGGTTACTTACAACAATAACATTACTTAAGAATGAAGTTATTTT\n+CTCAAAAACAGTGTCATTTTTATTAGCTTCATCTGGAGTTAATGTATCAAGGAAAGTTGA\n+TTTATACCATTCATCTAATTGAGACTTAACTTCTTTTGCATAAGTAGACGTTCCCGTTTC\n+GCCATAACTATAGTAGTTAAAGTATTCATAGATCTCGATAATAGCAATAAGATCTTGTAC\n+TGATCGAGGAGTTAAATCCCACGTGAATACCTTCGTACGGTTATCTGCGCCGCCATACAT\n+TGATCGAGCAGTGTTATAGATCTGCTCGTTATGGTCAGCCATTAATCCTTGAGTCAATGA\n+CTCTAATCCGCCAAAGACAGCAGTAGATGCAACGTTACTTAATACCCCTGTAGCAGTACC\n+GCCGCCACGAGAAATAAGTGAATCTCCAACGTCATTAAATTTATGAGAAACTGATTCAAC\n+ATCTGATTTCGAGCGTGGAAGTAAAATATTCACTACTGGAATTTTATCAACTTTATTAGT\n+ATTTGTTCCAGTGATTGATTTCACTACACTATTTGCAGTACGTTTCATTTCACCTAAACG\n+CATGCTACGCATATCACCGGTTGTACGAGAATTCATATCATACGCAGTGAACAACAACCC\n+GTTCTTATAAAGATCATGAACTCGTAAAGAACCAGATGTGTCATTACCAGCTGAACGTTC\n+AGACGGATATTGCGCAGTTATAGTGGATTTTATTTTTGCTGATTGTGAACTTTGACCAGC\n+GGAGGTTTTAACTCCGCTAATTAAAGCATCAGTCTTATCATCTAATTCTCTGACTTTAAT\n+GCTCATTAATTAACTCCTGTTGCCCCGAATACTCCAGGAGCTGGAGTAGCCGTGACTGTT\n+TGAACCTGGTGAATAGTCTTACTATTATTTACGTTATTAACCTGAGTGTTAGCAACATTC\n+ATATCACCGGTTGATTTTTTAGATTGCTCTTTAGCATTTTCAGCTTTTTGAATATTTTGA\n+ACTCGTTGATTATCTTCCGAAGTAGCTGGAGCCGCAGGCTTCGGAGTGTTATCTTCTTTG\n+AGCTTCTGATACTTGGATTCTACTCGTTGGAATCTTTTATCGAGTTCCTTTTTAGTAGCT\n+GGTTGATCACTTATAGCAGAATCACTAATAGACTTTTTGGCACTGTTATATGCCTTCTCT\n+AAAGATTGCATATTAGTTGGATTCTCTGGATCAACATCACCAATATATTTTTCTAAACGC\n+TGAACAGCTGCACGAGCTTCGTTTTGTTTGATCAGTGTTTCTTCGCGTTTTTCAGGAGCC\n+ATTGCTTTAAGATTCTGAGTCTCTTGATCACGGTCAGATGCTTGTGTAGAATCGATTTTA\n+TTCTCTCTTCCTAGTACCCAATCAAATGCACGAGTTTTAAATTCGCCAGCTTTATCAATA\n+ATTCCAGGACCTTCTTCAATACGCTTACTCTGATATTTAGCCAAAGCTTTTTGATCATCT\n+TCAGACAATGAATTACCAGTGCGTTCCTGGAATCCTTCTAGTGCTGAACCACGAATAGTA\n+GTTGCTGCATTTTCAAAGCCAAGTGCATCGAGTATAGAAGCAGATATCTTTGAAATTCCC\n+AA'..b'ATTTCCATGAGGTTACTGGGTTATGAGTTATAAAATTCTTTT\n+AGAAGTTACCGTGATGTCTTCGACTGGACATGTGGCGGTTAGTACTGAACAGCTGGATTT\n+TTATAGCTGGGATAATGCTAATATGTATTATGAAGCAGTAGAAGTTTATGAAGAAACGCC\n+AGATATTAAAGTATGGCGTCAAGTAACAAAACTTTATTAAAGCCCTTCGGGGCTTTTGTT\n+GTCTATAAATATAGTAAACTATAGAGGACTTTTTATGATCGAATTAAATGAAGTCTTCGA\n+TGAAGGGAAAGAACGTCTAGCAGTTACGAACCTTTATCCGAAGCTCAAGATTCCACAAAT\n+TTTTGCAATAGACAACACTAAAGTAGCTTATCGTATGTGCTCATATACTGGTGGTGGAGA\n+TGCAAATAAAAACATCAAACCCGGTGATAAAATGATGCATGTCATTGCATTAGGAGTTAC\n+TGATAAAGGCCTTGGTCAACTTAAGACCTTAGGTGATAATCCAATTGCTGTTATTGATAC\n+AATCTTTAACCACGTAATGGGTATCATGAAGTTTTATCGTTTTGACGCTGCTTTATTTCG\n+TGTTAAAAAGAATAAAACTGGTGGAGCAGGTCGCCAGATGCAAGTTATTGTTGATCGTCT\n+AATCAAGAAGAAAGGCGGTGGCAAATTCGTTATGCTTAAAGAGTTGTATGATTTTGATAA\n+GAAATACAACTACATTTTAGTATACAAGAAGAATGCTGATCTTGTCAATATCCCTGGAAT\n+GACTGAGATCATGGACTCAATTTATAAGAAAGTAGACACTGATGTAGGTGATGCTTATAT\n+CAACGTTGAGACCGGCAAACAAGTATCTAAGCTTGAAGCTATCGCGGGTTCAATCGCAGC\n+AGAAAATGATAAACGCTCAGACCAGGCGGTTGCGTCTCGAGCTAAAATATCTCGTCGTGC\n+TTTAATGGCTTCTCAATATTCAATCCAAGTGGGATTTGATACTCGTAAAGATGCGGTAGA\n+ACATGATAAGCGATTAGATGTAATTAACTCTAAACCTCCGGTTTATTTGACAGATAAGTC\n+TTCTGACCAAGTATCGAATATTCAAATGGCTATTGATAATTTCAGAAATGATTCTCAATC\n+AATTGCTAAAACCGGCGAAGCGTTTAAGACATTTGACCCGTCATGGAAAATGGATGATGA\n+TCGTCATTCTACTGGTACAATGAAAGCCCAAGAACTTGTTCTAAGGCTCACTAATATATT\n+AACCAGTGGAACAGTAGACGATTTCAGTCAACATCCTACTGATAGAAGAGAAGCATTTAA\n+AACATTAGCGGTCAGAGACATTTATCGTATTGGTGAAGCCTGGTCTAAATTAGAGCCTAA\n+TGACTATTATGGTGCTATTAAAGAACTTACTCGAGTCGCAATGGAAGACAAAGAATGGTC\n+TTCTGATGCAAATCGTGAATACGCAGTAAAAGAGATTGTAGAATTAATTTCTAAACAGTT\n+CTCTGATTTAGCAGCTAGCATGTACAAAAATACATCAGATGTGGATCGTTATACTCCGGT\n+ACAATTGTCAGGTTTACATGCTTACGTCGGTTCATCTTATAAGTACATCAACGACTATCT\n+TTTAGGCCTTGATGATTATGGCAAAGAAACTGTTGAAAAATGGATTGAGTCTATCGATTC\n+TGCGTTTGAAAATGGTGTTCGTCTTCCGAAGGGAACTAAGCTATTTCGAGGTCAACATAC\n+TAAGCGCGAAGCTATTGAAGTTAGTTTAGAAAACAAGCACTTCTATTTCAAGAATTATGT\n+GTCAACTTCAATGGCTCCTATTATCTTTGGTGGATATGGACGAGCATATGATGCAATGGA\n+CCCCGCTGCATTGAACACAGATACATCGACTCCTAAAGAAGTGCTTGACTCTGTTTCAAC\n+TGTTCGGCCTGATAGTATTACTAACTCTGAAATGGGTGAATTGCGTTTAGCGTTCGTTAT\n+TTCTGGCGCAGAGAAAATAAAGACTATCGTAACCAATGCTGGAATCTCAGGATTGTCATT\n+TGAAGCTGAAGTTATTCTTCCTCGTGGTACTGTTCTTAGAATTGATAAAATGTATGGAAC\n+AGCTCAGAAACTTCAAGCTAATGACTACACAGCATCAAAGAGTGTTCTTATGGAATGCAC\n+TGTAGTATCTCCAGAACAATTATCTGAAACTACAATTTATGATGGCGATAAATTGTTAGA\n+AGGTGAATTGGTTGAATCTGATTATTCGTTCAGTTCTTTTATTGGTCAATTAAATGAAGC\n+TAAAGTTGAAACACCAGATTGGTTAGGTGAAGCTCTAGCATCATTTGTTGACATAAATAA\n+TTTACCAGAACGATTCATAAATTAATATTTTCACATGGACGTGAATTCAGAGAGGGCTTT\n+ATGGAAATTTTAAACGAAGTACTAGACGAAAGTAAACTGGATTTACCAGTTACGAACCTT\n+TATCCAAAGACGAAAATTCCACAAATTTTTGCTATTCAAACTAACTCCGAGGGTTCACTG\n+CCAGCATTCAGGATGTGTTCATATACATCTGGCGGTGATACCAATAAGAACGTTAAACCT\n+GGCGACAAAATGATTCATGTTGTTATGCTATCATTGAGCGAAAAAGGATCATTAGTTAAG\n+CTTAAAAACTTAGGCGGCGATCCAATTGGTGTTATCTCTACTACGTTCAATATCGTTTAT\n+TCAACGATGAAGCAGTATAAAATGGACGCATGCTTGTTCCGAATGGCCAAAAGCAAAATC\n+GGTGGACAAGCTCGTCAGATGCAGGTTATTATGGACCGACTCGTACGTTCTCGTACTGGT\n+GGTAAATTTGTTATCCTGAAAGAACTCTGGGATTATGATAAGAAGTACGCATATATTCTT\n+ATTCATCGTAAAAATGTTGATCTCTCAACCATCCCTGGCGTCCCAGAGATTGATACTGGA\n+CTGTTCACTGCAGTTGAAACTAAAGTTGGTGAAGTTTATGTTGAAAAGAAATCAGGTCAA\n+CAAGTAACTAAAGCCCAAGCCGTTGCTGCTTCTATTGCAGTCGAAAACGATAAGCGTTCA\n+GATCAAAACGTTATTTCTCGTGCTAAGATAAATCGTCGTCAAGCTATTGCTGCTCAGTAT\n+TCTGTTGATGCATCTAGCATCCAAGGCGATGATCGTGCTGCTGAAGAATTTAAACGCTTA\n+GAAGCTAAAGTTCCAGTTAAAAGCTCTAAAGGCGCTGAGTCATCAGACATGGTAGCAAAA\n+GTTAATACCATCGCTGACCGTCAAGGAAATGAGTATATCGGCAAAGTACTAAACTTCATC\n+ACTAATCCTGAAACATCTCAGGACACAGATGGTAAAGCATTGACTGCACGAATAGGTCAA\n+TTGCGCCAGTTATCTAAAATGCCTAAAGGTGCCATGTTATCAGGTGGATTTGAAACTGGT\n+GGTATGAAGTACTACATGGAAAACCAAAAAGAAATGTACAATGAAGTTCGTTCATTTGCT\n+CGATTGATAGCTGGGGTGAATACAACTAACTCCTTTCAGACGATGAAAGATTTAGTTAAA\n+ATGGCTTCAGCTGGAACTAGACCTGAAGATCGTGAACAGTTAATTGCAAATTTAATTGGA\n+TTAGCTTATAAAGAAATAAGTGCAATCATCAGAGATTCATACCAAACTGCAGCAAGTTTA\n+TCTAAAGAGAATGATCATTATTCTAAAGATGAAAAACAAGCTATCAGTGAATACTGCGCA\n+AACGCTTTCGAATACGTGAATATGTTCTTAATCGGTAAGCCGGAAGAAGGGTATTCAACT\n+TCTGATTCTCTCGAGATCATCGATAATATGGACTCTGCGTTTGAAAAAGGAACTCGTTTA\n+GACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACA\n'
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/seq/genome.fasta.fai
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/seq/genome.fasta.fai Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,1 @@
+Merlin 172788 8 60 61
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/seq/refSeqs.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/seq/refSeqs.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,1 @@
+[{"end":172788,"length":172788,"line_byte_length":"61","line_length":"60","name":"Merlin","offset":"8","start":0}]
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/data/trackList.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/data/trackList.json Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,170 @@
+{
+   "formatVersion" : 1,
+   "hideGenomeOptions" : false,
+   "names" : {
+      "type" : "Hash",
+      "url" : "names/"
+   },
+   "plugins" : [
+      {
+         "location" : "https://cdn.jsdelivr.net/gh/TAMU-CPT/blastview@97572a21b7f011c2b4d9a0b5af40e292d694cbef/",
+         "name" : "BlastView"
+      }
+   ],
+   "refSeqs" : "seq/genome.fasta.fai",
+   "shareLink" : true,
+   "show_menu" : true,
+   "show_nav" : true,
+   "show_overview" : true,
+   "show_tracklist" : true,
+   "tracks" : [
+      {
+         "category" : "Reference sequence",
+         "codonStarts" : [
+            "TTG",
+            "CTG",
+            "ATG"
+         ],
+         "codonStops" : [
+            "TAA",
+            "TAG",
+            "TGA"
+         ],
+         "codonTable" : {
+            "AAA" : "K",
+            "AAC" : "N",
+            "AAG" : "K",
+            "AAT" : "N",
+            "ACA" : "T",
+            "ACC" : "T",
+            "ACG" : "T",
+            "ACT" : "T",
+            "AGA" : "R",
+            "AGC" : "S",
+            "AGG" : "R",
+            "AGT" : "S",
+            "ATA" : "I",
+            "ATC" : "I",
+            "ATG" : "M",
+            "ATT" : "I",
+            "CAA" : "Q",
+            "CAC" : "H",
+            "CAG" : "Q",
+            "CAT" : "H",
+            "CCA" : "P",
+            "CCC" : "P",
+            "CCG" : "P",
+            "CCT" : "P",
+            "CGA" : "R",
+            "CGC" : "R",
+            "CGG" : "R",
+            "CGT" : "R",
+            "CTA" : "L",
+            "CTC" : "L",
+            "CTG" : "L",
+            "CTT" : "L",
+            "GAA" : "E",
+            "GAC" : "D",
+            "GAG" : "E",
+            "GAT" : "D",
+            "GCA" : "A",
+            "GCC" : "A",
+            "GCG" : "A",
+            "GCT" : "A",
+            "GGA" : "G",
+            "GGC" : "G",
+            "GGG" : "G",
+            "GGT" : "G",
+            "GTA" : "V",
+            "GTC" : "V",
+            "GTG" : "V",
+            "GTT" : "V",
+            "TAC" : "Y",
+            "TAT" : "Y",
+            "TCA" : "S",
+            "TCC" : "S",
+            "TCG" : "S",
+            "TCT" : "S",
+            "TGC" : "C",
+            "TGG" : "W",
+            "TGT" : "C",
+            "TTA" : "L",
+            "TTC" : "F",
+            "TTG" : "L",
+            "TTT" : "F"
+         },
+         "faiUrlTemplate" : "seq/genome.fasta.fai",
+         "key" : "Reference sequence",
+         "label" : "DNA",
+         "metadata" : {
+            "dataset_edam_format" : "<a target=\"_blank\" href=\"http://edamontology.org/format_1929\">fasta</a>",
+            "dataset_file_ext" : "fasta",
+            "dataset_hid" : "1",
+            "dataset_id" : "7495a4247e72f5f1",
+            "dataset_size" : "171.6 KB",
+            "history_display_name" : "<a target=\"_blank\" href=\"http://localhost/history/view/d29e465b351a50c9\">Unnamed history</a>",
+            "history_id" : "d29e465b351a50c9",
+            "history_user_email" : "<a href=\"mailto:anthony.bretaudeau@irisa.fr\">anthony.bretaudeau@irisa.fr</a>",
+            "history_user_id" : "17",
+            "metadata_data_lines" : "2881",
+            "metadata_dbkey" : "?",
+            "metadata_sequences" : "1",
+            "tool_tool" : "<a target=\"_blank\" href=\"http://localhost/datasets/7495a4247e72f5f1/show_params\">upload1</a>",
+            "tool_tool_id" : "upload1",
+            "tool_tool_version" : "1.1.6"
+         },
+         "seqType" : "dna",
+         "storeClass" : "JBrowse/Store/SeqFeature/IndexedFasta",
+         "type" : "SequenceTrack",
+         "urlTemplate" : "seq/genome.fasta",
+         "useAsRefSeqStore" : 1
+      },
+      {
+         "category" : "Default",
+         "key" : "merlin.gff",
+         "label" : "4ced49b280a72a29f1b922ae1a9664c8_0",
+         "maxHeight" : "600",
+         "menuTemplate" : [
+            {},
+            {},
+            {},
+            {}
+         ],
+         "metadata" : {
+            "dataset_edam_format" : "<a target=\"_blank\" href=\"http://edamontology.org/format_1975\">gff3</a>",
+            "dataset_file_ext" : "gff3",
+            "dataset_hid" : "2",
+            "dataset_id" : "b02ee2031011d9cf",
+            "dataset_size" : "110.3 KB",
+            "history_display_name" : "<a target=\"_blank\" href=\"http://localhost/history/view/d29e465b351a50c9\">Unnamed history</a>",
+            "history_id" : "d29e465b351a50c9",
+            "history_user_email" : "<a href=\"mailto:anthony.bretaudeau@irisa.fr\">anthony.bretaudeau@irisa.fr</a>",
+            "history_user_id" : "17",
+            "metadata_attributes" : "4",
+            "metadata_columns" : "9",
+            "metadata_comment_lines" : "2",
+            "metadata_data_lines" : "1228",
+            "metadata_dbkey" : "?",
+            "metadata_delimiter" : "__tc__",
+            "tool_tool" : "<a target=\"_blank\" href=\"http://localhost/datasets/b02ee2031011d9cf/show_params\">upload1</a>",
+            "tool_tool_id" : "upload1",
+            "tool_tool_version" : "1.1.6"
+         },
+         "overrideDraggable" : false,
+         "overridePlugins" : false,
+         "storeClass" : "JBrowse/Store/SeqFeature/GFF3Tabix",
+         "style" : {
+            "className" : "feature",
+            "color" : "#a6cee3",
+            "description" : "note,description",
+            "label" : "product,name,id"
+         },
+         "trackType" : "NeatHTMLFeatures/View/Track/NeatFeatures",
+         "type" : "NeatHTMLFeatures/View/Track/NeatFeatures",
+         "urlTemplate" : "raw/4ced49b280a72a29f1b922ae1a9664c8_0.gff.gz"
+      }
+   ],
+   "view" : {
+      "trackPadding" : 20
+   }
+}
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/galaxy.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/galaxy.xml Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<root>
+    <metadata>
+        <gencode>1</gencode>
+        <genomes>
+              <genome path="/opt/galaxy-dist/database/files/002/188/dataset_2188862.dat">
+                <metadata>
+                  <dataset id="7495a4247e72f5f1" hid="1"
+                      size="171.6 KB"
+                      edam_format="format_1929"
+                      file_ext="fasta" />
+                  <history id="d29e465b351a50c9"
+                      user_email="anthony.bretaudeau@irisa.fr"
+                      user_id="17"
+                      display_name="Unnamed history"/>
+                  <metadata
+                      dbkey="?"
+                      data_lines="2881"
+                      sequences="1"
+                      />
+                  <tool
+                      tool_id="upload1"
+                      tool_version="1.1.6"
+                      />
+                </metadata>
+              </genome>
+        </genomes>
+        <general>
+            <defaultLocation></defaultLocation>
+            <trackPadding>20</trackPadding>
+
+            <shareLink>true</shareLink>
+            <aboutDescription></aboutDescription>
+            <show_tracklist>true</show_tracklist>
+            <show_nav>true</show_nav>
+            <show_overview>true</show_overview>
+            <show_menu>true</show_menu>
+            <hideGenomeOptions>false</hideGenomeOptions>
+        </general>
+        <galaxyUrl>http://localhost</galaxyUrl>
+    </metadata>
+    <tracks>
+        <track cat="Default" format="gene_calls" visibility="default_off">
+            <files>
+              <trackFile path="/opt/galaxy-dist/database/files/002/188/dataset_2188863.dat" ext="gff3" label="merlin.gff">
+                <metadata>
+                  <dataset id="b02ee2031011d9cf" hid="2"
+                      size="110.3 KB"
+                      edam_format="format_1975"
+                      file_ext="gff3" />
+                  <history id="d29e465b351a50c9"
+                      user_email="anthony.bretaudeau@irisa.fr"
+                      user_id="17"
+                      display_name="Unnamed history"/>
+                  <metadata
+                      dbkey="?"
+                      data_lines="1228"
+                      comment_lines="2"
+                      columns="9"
+                      delimiter="__tc__"
+                      attributes="4"
+                      />
+                  <tool
+                      tool_id="upload1"
+                      tool_version="1.1.6"
+                      />
+                </metadata>
+              </trackFile>
+            </files>
+
+            <options>
+                <style>
+                    <overridePlugins>False</overridePlugins>
+                    <overrideDraggable>False</overrideDraggable>
+                    <className>feature</className>
+                    <description>note,description</description>
+                    <label>product,name,id</label>
+                    <height>10px</height>
+                    <maxHeight>600</maxHeight>
+                </style>
+                <scaling>
+                        <method>ignore</method>
+                        <scheme>
+                            <color>__auto__</color>
+                        </scheme>
+                </scaling>
+                <menus>
+                </menus>
+                <custom_config>
+                </custom_config>
+
+                <gff>
+                    <trackType>NeatHTMLFeatures/View/Track/NeatFeatures</trackType>
+                    <index>false</index>
+                </gff>
+            </options>
+        </track>
+    </tracks>
+    <plugins
+        ComboTrackSelector=""
+        Bookmarks=""
+        GCContent=""
+        BlastView="True"
+        theme=""
+        />
+</root>
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/jbrowse.conf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/jbrowse.conf Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,110 @@
+#### JBrowse main configuration file
+
+## uncomment the section below to customize this browser's title and description
+# [aboutThisBrowser]
+# title = <i>Oryza sativa</i>
+# description = Browser for O. sativa transcripts and RNA-seq data,
+#   produced by the Smith laboratory at Example State University.
+
+## uncomment and edit the example below to configure a faceted track selector
+# [trackSelector]
+# type = Faceted
+# displayColumns =
+#   + label
+#   + key
+#   + organism
+#   + technique
+## optionally sort the faceted track selector by column (use the names from displayColumns)
+# initialSortColumn=label
+## optionally give different names to some of the data facets using renameFacets
+# [trackSelector.renameFacets]
+# submission = Submission ID
+# developmental-stage = Conditions
+# cell-line = Cell Line
+# key = Dataset
+# label = Track
+
+## uncomment this section to get hierarchical trackselector options
+# [trackSelector]
+## optionally turn off sorting for the hierarchical track selector
+# sortHierarchical = false
+## set collapsed categories for the hierarchical track selector
+# collapsedCategories = Reference sequence,Quantitative / XY Plot
+## set category ordering in the hierarchical track selector
+# categoryOrder = BAM, Transcripts, Quantitative/Density, VCF
+
+## configure where to get metadata about tracks.  always indexes the
+## `metadata` part of each track config, but this can be used to load
+## additional metadata from CSV or JSON urls
+# [trackMetadata]
+# sources = data/trackMetadata.csv
+
+
+[GENERAL]
+
+
+## add a document.domain to set the same-origin policy
+# documentDomain=foobar.com
+
+## use classic jbrowse menu with file instead of track and genome
+#classicMenu = true
+
+## hide open genome option
+#hideGenomeOptions = true
+
+## enable or disable high resolution rendering for canvas features. set to auto, disabled, or numerical scaling factor. default: 2
+# highResolutionMode=auto
+
+## uncomment to change the default sort order of the reference
+## sequence dropdown
+# refSeqOrder = length descending
+
+## Uncomment to prevent HTML tracks from displaying gene subfeatures (enabled by default)
+# inferHTMLSubfeatures = false
+
+## to set a default data directory other than 'data', uncomment and
+## edit the line below
+# dataRoot = data
+
+## optionally add more include statements to load and merge in more
+## configuration files
+include  = {dataRoot}/trackList.json
+include += {dataRoot}/tracks.conf
+# include += ../url/of/my/other/config.json
+# include += another_config.conf
+
+## uncomment and edit the example below to enable one or more
+## JBrowse plugins
+# [ plugins.MyPlugin ]
+# location = plugins/MyPlugin
+# [ plugins.AnotherPlugin ]
+# location = ../plugin/dir/someplace/else
+
+## edit the datasets list below to add datasets to the jbrowse dataset
+## selector
+
+# [datasets.volvox]
+# url  = ?data=sample_data/json/volvox
+# name = Volvox Example
+
+# [datasets.modencode]
+# url  = ?data=sample_data/json/modencode
+# name = MODEncode Example
+
+# [datasets.yeast]
+# url  = ?data=sample_data/json/yeast
+# name = Yeast Example
+[ plugins.BlastView ]
+location = ../plugin/BlastView/
+[ plugins.GCContent ]
+location = ../plugin/GCContent/
+[ plugins.ComboTrackSelector ]
+location = ../plugin/ComboTrackSelector/
+[ plugins.MultiBigWig ]
+location = ../plugin/MultiBigWig/
+[ plugins.bookmarks ]
+location = ../plugin/bookmarks/
+[ plugins.NeatCanvasFeatures ]
+location = ../plugin/NeatCanvasFeatures/
+[ plugins.NeatHTMLFeatures ]
+location = ../plugin/NeatHTMLFeatures/
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/dataset_1_files/jbrowse_conf.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/dataset_1_files/jbrowse_conf.json Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,9 @@
+// top-level JBrowse configuration file.  Treated the same as
+// jbrowse.conf, but this one is in JSON format.
+//
+// Unless generating configuration from scripts, most users will
+// prefer to add variables to jbrowse.conf instead of this file, since
+// jbrowse.conf is much easier to hand-edit.
+{
+
+}
\ No newline at end of file
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/export/cdna.fa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/export/cdna.fa Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,103 @@
+>ff2fe902-7bab-431c-be82-30ed072915d1 (mRNA) 690 residues [Merlin:2-691 + strand] [cdna] name=Unknown
+CGTTTAGACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACATTCGAG
+CATAACGCAGAGAATAAGTTGTTCTATTTCAGAAACTACGTTTCAACTTCATTAAAGCCT
+CTGATCTTTGGTGAATTTGGTCGTATGTTTATGGCACTAGATGACGATACTACAATTTAT
+ACTGCTGAGACGCCTGATGATTATAATCGTTTCGCAAACCCAGAAGATATAATTGATATT
+GGCGCTACTCAAAAAGACTCATTTGACGATAACAATAATGATGGAACATCTATTAATATC
+GGCAAACAAGTTAATTTAGGATTCGTTATTTCCGGTGCTGAAAATGTTCGAGTTATTGTT
+CCAGGTTCTTTAACTGAATATCCAGAAGAAGCGGAAGTTATTCTGCCTCGTGGTACTCTT
+TTGAAGATCAATAAAATCACTACTCAAGTAGATAAACGCTCGAATAAGTTCATGGTTGAA
+GGTTCAATCGTTCCGCCTTCTGAGCAAATTGATGAATCTGTTGAGATTTATGACGGTGAT
+CTGTTCATGGAAACAGGTGAAGTAGTAAAACTGTCCGGATTCATGCAGTTCGTCAACGAA
+TCTGCATACGATGAAGAGCAAAACCAGATGGCTGCTGAGATTCTGTCTGGATTCTTGGAC
+ATTGATGACATGCCACGTAAGTTCCGCTAG
+>f2e1909a-1d40-4a49-a67b-5fe2afdc4957 (mRNA) 288 residues [Merlin:752-1039 + strand] [cdna] name=Unknown
+ATGAAATCAATTTTTCGTATCAACGGTGTAGAAATTGTAGTTGAAGATGTAGTTCCTATG
+TCTTATGAATTCAATGAAGTTGTTTTCAAAGAGCTTAAGAAAATTTTAGGCGATAAGAAG
+CTTCAAAGTACTCCAATTGGACGTTTTGGAATGAAAGAAAACGTTGATACTTATATTGAA
+AGTGTAGTGACAGGGCAGTTAGAAGGTGAATTTTCTGTAGCAGTTCAAACTGTAGAAAAT
+GATGAAGTTATTTTAACTTTACCAGCTTTCGTAATTTTCCGCAAATAA
+>12fe0db6-c8e1-4bc9-b594-87c92c6c9669 (mRNA) 945 residues [Merlin:1067-2011 - strand] [cdna] name=Unknown
+ATGCTAACTTTAGATGAATTTAAAAACCAAGCGGGTAATATAGACTTTCAGCGTACTAAT
+ATGTTTAGTTGTGTATTTGCAACTACTCCGTCAGCAAAGTCTCAACAATTACTCGATCAA
+TTTGGCGGTATGCTCTTTAATAACCTTCCGTTGAATAATGACTGGCTTGGATTAACACAA
+GGTGAGTTCACATCAGGACTCACCTCAATTATCACTGCCGGTACTCAACAGCTGGTAAGA
+AAGTCTGGTGTATCGAAATATCTTATTGGAGCAATGAGCAATCGTGTTGTTCAGTCTTTA
+TTAGGTGAATTTGAAGTCGGAACTTATTTGTTAGACTTCTTTAACATGGCTTATCCGCAA
+TCTGGATTGATGATTTATTCGGTCAAAATTCCAGAGAACAGATTGTCTCATGAAATGGAT
+TTCAACCATAACTCACCGAATATTAGAATAACTGGACGTGAACTCGATCCGTTAACTATA
+TCATTCAGAATGGATCCCGAAGCAAGTAACTATCGTGCAATGCAAGATTGGGTGAACTCC
+GTTCAAGACCCGGTTACTGGATTGCGAGCATTACCAACTGACGTCGAAGCTGACATTCAG
+GTTAACCTTCATGCTCGAAATGGATTACCTCATACTGTGATAATGTTCACAGGTTGTGTT
+CCTGTTGCGTGTGGAGCTCCTGAGCTTACATATGAAGGAGATAACCAAATTGCGGTTTTC
+GATGTTACATTTGCTTACAGAGTAATGCAAACGGGTGCTGTTGGACGTCAAGCTGCTCTT
+GATTGGATTGAAGATAGAGCTGTTAATTCTATAACTGGAATTAATAGTGAAATGTCTCTT
+AATGGAAGTTTAAGTAGATTATCTAGACTTGGAGGAGCTGCTGGAGGGTTGTCTCACGTC
+ATTAATTCGACCCGAAACTCTACTTCGAAAATACTTGGATTGTAA
+>58fc8255-95ed-4417-a373-238f826810ac (mRNA) 1056 residues [Merlin:2011-3066 - strand] [cdna] name=Unknown
+ATGAGCATTAAAGTCAGAGAATTAGATGATAAGACTGATGCTTTAATTAGCGGAGTTAAA
+ACCTCCGCTGGTCAAAGTTCACAATCAGCAAAAATAAAATCCACTATAACTGCGCAATAT
+CCGTCTGAACGTTCAGCTGGTAATGACACATCTGGTTCTTTACGAGTTCATGATCTTTAT
+AAGAACGGGTTGTTGTTCACTGCGTATGATATGAATTCTCGTACAACCGGTGATATGCGT
+AGCATGCGTTTAGGTGAAATGAAACGTACTGCAAATAGTGTAGTGAAATCAATCACTGGA
+ACAAATACTAATAAAGTTGATAAAATTCCAGTAGTGAATATTTTACTTCCACGCTCGAAA
+TCAGATGTTGAATCAGTTTCTCATAAATTTAATGACGTTGGAGATTCACTTATTTCTCGT
+GGCGGCGGTACTGCTACAGGGGTATTAAGTAACGTTGCATCTACTGCTGTCTTTGGCGGA
+TTAGAGTCATTGACTCAAGGATTAATGGCTGACCATAACGAGCAGATCTATAACACTGCT
+CGATCAATGTATGGCGGCGCAGATAACCGTACGAAGGTATTCACGTGGGATTTAACTCCT
+CGATCAGTACAAGATCTTATTGCTATTATCGAGATCTATGAATACTTTAACTACTATAGT
+TATGGCGAAACGGGAACGTCTACTTATGCAAAAGAAGTTAAGTCTCAATTAGATGAATGG
+TATAAATCAACTTTCCTTGATACATTAACTCCAGATGAAGCTAATAAAAATGACACTGTT
+TTTGAGAAAATAACTTCATTCTTAAGTAATGTTATTGTTGTAAGTAACCCTACTGTGTGG
+TTCGTCAGAAACTTTGGAACCACAAGTAAATTCGATGGACGTGCTGAAGTATTCGGTCCA
+TGTCAAATTCAGAGTATCCGTTTTGATAAAACTCCAAATGGAAACTTTAACGGTTTAGCT
+ATAGCTCCAAACCTGCCAAGTACATTCACATTAGAAATTACTATGCGTGAAATCTTGACA
+TTGAACCGAGCTTCAGTATATGCGGAAGGATTCTGA
+>c009dd7a-3284-4e7f-9ee1-3b56e2598e07 (mRNA) 1662 residues [Merlin:3066-4796 - strand] [cdna] name=multiexongene
+ATGAAAAGCGAAAACATGTCCACAATGAGACGTCGTAAAGTTATCGCTGATTCAAAGGGT
+GAAAGAGATGCAGCCTCGACTGCATCTGATCAAGTAGACTCTTTAGAATTAATCGGCCTT
+AAACTTGATGATGTACAAAGCGCTAATGAACTAGTTGCTGAAGTAATTGAAGAAAAGGGC
+AATAACTTAATTGATTCAGTTGATAACGTCGCTGAAGGTACTGAATTAGCTGCTGAAGCA
+TCTGAACGAACTACTGAGTCTATCAAGACTCTTACTGGCGTAGCGTCAACAATCAGCGAC
+AAATTAAGTAAACTCGCTTCGATGCTCGAGTCGAAGGTTCAGGCTGTGGAGCAAAAAGTA
+CAAGAATCTGGTGCCTCAGCTTCAACTGGGCTGTCAGTGATAGAAGATAAGCTTCCAGAT
+CCTGATGAGCCTTTCTTTCCACCTGTCCCTCAGGAACCCGAGAACAACAAGAAAGATCAA
+AAGAAAGATGATAAGAAACCTACCGATATGTTAGGTGACTTGCTGAAGACTACGAAGGGC
+GGATTTAAAGCTACGATATCAATCACTGATAAAATATCGTCTATGCTTTTCAAATACACC
+GTAACAGCATTAGCTGAAGCTGCTAAAATGGCTGCTATGCTATTTGCATTAGTATTAGGC
+ATAGATTTACTTCGTATTCATTTTAAGTATTGGACTGATAAATTCATGAGTAACTTCGAT
+GAATTCAGTGCTGAAGCTGGTGAATGGGGTGGACTGCTTCAATCAATTTTTGGAATGTTA
+GGAGATATTAAAAAGTTCTGGGAAGCTGGAGACTGGAGTGGATTAGCAGTAGCTATTGTC
+AAAGGATTAGCTGATGTGATTTACAACCTGAGCGAAATAATGTCTTTGGGAATTTCAAAG
+ATATCTGCTTCTATACTCGATGCACTTGGCTTTGAAAATGCAGCAACTACTATTCGTGGT
+TCAGCACTAGAAGGATTCCAGGAACGCACTGGTAATTCATTGTCTGAAGATGATCAAAAA
+GCTTTGGCTAAATATCAGAGTAAGCGTATTGAAGAAGGTCCTGGAATTATTGATAAAGCT
+GGCGAATTTAAAACTCGTGCATTTGATTGGGTACTAGGAAGAGAGAATAAAATCGATTCT
+ACACAAGCATCTGACCGTGATCAAGAGACTCAGAATCTTAAAGCAATGGCTCCTGAAAAA
+CGCGAAGAAACACTGATCAAACAAAACGAAGCTCGTGCAGCTGTTCAGCGTTTAGAAAAA
+TATATTGGTGATGTTGATCCAGAGAATCCAACTAATATGCAATCTTTAGAGAAGGCATAT
+AACAGTGCCAAAAAGTCTATTAGTGATTCTGCTATAAGTGATCAACCAGCTACTAAAAAG
+GAACTCGATAAAAGATTCCAACGAGTAGAATCCAAGTATCAGAAGCTCAAAGAAGATAAC
+ACTCCGAAGCCTGCGGCTCCAGCTACTTCGGAAGATAATCAACGAGTTCAAAATATTCAA
+AAAGCTGAAAATGCTAAAGAGCAATCTAAAAAATCAACCGGTGATATGAATGTTGCTAAC
+ACTCAGGTTAATAACGTAAATAATAGTAAGACTATTCACCAGGTTCAAACAGTCACGGCT
+ACTCCAGCTCCTGGAGTATTCGGGGCAACAGGAGTTAATTAA
+>2706ea76-172a-48c1-b940-eb603996f082 (mRNA) 1056 residues [Merlin:5011-6066 - strand] [cdna] name=cds-not-under-exon
+CTTTAATGACGCTGGTGAATCAATAAAAGAGATGATCGGTGCAATTTATGAATCAAAACC
+TCTTATAGCACCTGCGATGAACACAATCAACACATATGTTCCTCGAGTTCCATGGACGAG
+TAACATAACTGAATACAAGAAATATGTTCGAGATGTTGCATTAGCAGTAGATAATGACCA
+ATTCGTTTTTGTATGGGAAGATATCTATGGCTTGAACATGATGGATTATGACGCAATGAT
+TAACCAAGAATCAATCAAGGTTATTGTCGGTGAACCACGCACAATAGGTCAATTTGTCGG
+TGAGCTGGAATATAATCTCGCTTATGACTTCCAGTGGTTAACGAAGGCTAATGCCCATAC
+ACGCGATCCTATTTTTAACGCTACAATCTATTCACACTCATTCTTGGATAATAACCTTCC
+TAGAATAGTAACAGGTGATGGACAGAATAGCATCTTCGTTTCTCGCTCGGGTGCATATTC
+TGAAATGACTTATCGAAATGGATATGAAGAAGCTATCAGGCTTCAGACTATGGCACAATA
+CGACGGTTATGCAACTTGTAAAATGGTTGGAGACTTTGAAATGACTCCTGGAGATAAGAT
+TAATTTCTTTGATCCAAAGAAACAATTCAAAGCTGATTTTTACATTGATGAAGTAATTCA
+TGAAGTAAGTAATAACCAAAGCATAACTACACTTTATATGTTTACTAACTCTCGTAAGTT
+GGAAACAGTAGAACCAATAAAGGTTAAAAATGAACTTAAATCTGATACTACCACTTAAGA
+AAATACAAGTCAATGGCAAAACCATTTCTATTCCTAAGCTTGGCTTGAAGCATCACACGT
+TGATTAAAGATGTTCGTGCAATGGATGAGAACATGGGAATTCTTTTGGACTCAATTCATC
+CTGGGCTAAACGCTGCTGAATCAGATTTAGTGTCTATTCATTTGCTAGAGTTCAATGGCA
+AGTTAAAATCAAGTGTCGTTAAAGATGGATACACTTACAATATCAATGACATTTATATTT
+GCCAACGCCTTGAATTCCAGTTCCAAGGAAAGACAT
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/export/cds.fa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/export/cds.fa Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,68 @@
+>ff2fe902-7bab-431c-be82-30ed072915d1 (mRNA) 690 residues [Merlin:2-691 + strand] [cds] name=Unknown
+CGTTTAGACAAAGGTACATTATTGTATCGTGGCCAAAAATTAGACCTTCCTACATTCGAG
+CATAACGCAGAGAATAAGTTGTTCTATTTCAGAAACTACGTTTCAACTTCATTAAAGCCT
+CTGATCTTTGGTGAATTTGGTCGTATGTTTATGGCACTAGATGACGATACTACAATTTAT
+ACTGCTGAGACGCCTGATGATTATAATCGTTTCGCAAACCCAGAAGATATAATTGATATT
+GGCGCTACTCAAAAAGACTCATTTGACGATAACAATAATGATGGAACATCTATTAATATC
+GGCAAACAAGTTAATTTAGGATTCGTTATTTCCGGTGCTGAAAATGTTCGAGTTATTGTT
+CCAGGTTCTTTAACTGAATATCCAGAAGAAGCGGAAGTTATTCTGCCTCGTGGTACTCTT
+TTGAAGATCAATAAAATCACTACTCAAGTAGATAAACGCTCGAATAAGTTCATGGTTGAA
+GGTTCAATCGTTCCGCCTTCTGAGCAAATTGATGAATCTGTTGAGATTTATGACGGTGAT
+CTGTTCATGGAAACAGGTGAAGTAGTAAAACTGTCCGGATTCATGCAGTTCGTCAACGAA
+TCTGCATACGATGAAGAGCAAAACCAGATGGCTGCTGAGATTCTGTCTGGATTCTTGGAC
+ATTGATGACATGCCACGTAAGTTCCGCTAG
+>f2e1909a-1d40-4a49-a67b-5fe2afdc4957 (mRNA) 9 residues [Merlin:752-1039 + strand] [cds] name=Unknown
+AAATTTTAG
+>12fe0db6-c8e1-4bc9-b594-87c92c6c9669 (mRNA) 108 residues [Merlin:1067-2011 - strand] [cds] name=Unknown
+CACCTCAATTATCACTGCCGGTACTCAACAGCTGGTAAGAAAGTCTGGTGTATCGAAATA
+TCTTATTGGAGCAATGAGCAATCGTGTTGTTCAGTCTTTATTAGGTGA
+>58fc8255-95ed-4417-a373-238f826810ac (mRNA) 1056 residues [Merlin:2011-3066 - strand] [cds] name=Unknown
+ATGAGCATTAAAGTCAGAGAATTAGATGATAAGACTGATGCTTTAATTAGCGGAGTTAAA
+ACCTCCGCTGGTCAAAGTTCACAATCAGCAAAAATAAAATCCACTATAACTGCGCAATAT
+CCGTCTGAACGTTCAGCTGGTAATGACACATCTGGTTCTTTACGAGTTCATGATCTTTAT
+AAGAACGGGTTGTTGTTCACTGCGTATGATATGAATTCTCGTACAACCGGTGATATGCGT
+AGCATGCGTTTAGGTGAAATGAAACGTACTGCAAATAGTGTAGTGAAATCAATCACTGGA
+ACAAATACTAATAAAGTTGATAAAATTCCAGTAGTGAATATTTTACTTCCACGCTCGAAA
+TCAGATGTTGAATCAGTTTCTCATAAATTTAATGACGTTGGAGATTCACTTATTTCTCGT
+GGCGGCGGTACTGCTACAGGGGTATTAAGTAACGTTGCATCTACTGCTGTCTTTGGCGGA
+TTAGAGTCATTGACTCAAGGATTAATGGCTGACCATAACGAGCAGATCTATAACACTGCT
+CGATCAATGTATGGCGGCGCAGATAACCGTACGAAGGTATTCACGTGGGATTTAACTCCT
+CGATCAGTACAAGATCTTATTGCTATTATCGAGATCTATGAATACTTTAACTACTATAGT
+TATGGCGAAACGGGAACGTCTACTTATGCAAAAGAAGTTAAGTCTCAATTAGATGAATGG
+TATAAATCAACTTTCCTTGATACATTAACTCCAGATGAAGCTAATAAAAATGACACTGTT
+TTTGAGAAAATAACTTCATTCTTAAGTAATGTTATTGTTGTAAGTAACCCTACTGTGTGG
+TTCGTCAGAAACTTTGGAACCACAAGTAAATTCGATGGACGTGCTGAAGTATTCGGTCCA
+TGTCAAATTCAGAGTATCCGTTTTGATAAAACTCCAAATGGAAACTTTAACGGTTTAGCT
+ATAGCTCCAAACCTGCCAAGTACATTCACATTAGAAATTACTATGCGTGAAATCTTGACA
+TTGAACCGAGCTTCAGTATATGCGGAAGGATTCTGA
+>c009dd7a-3284-4e7f-9ee1-3b56e2598e07 (mRNA) 1662 residues [Merlin:3066-4796 - strand] [cds] name=multiexongene
+ATGAAAAGCGAAAACATGTCCACAATGAGACGTCGTAAAGTTATCGCTGATTCAAAGGGT
+GAAAGAGATGCAGCCTCGACTGCATCTGATCAAGTAGACTCTTTAGAATTAATCGGCCTT
+AAACTTGATGATGTACAAAGCGCTAATGAACTAGTTGCTGAAGTAATTGAAGAAAAGGGC
+AATAACTTAATTGATTCAGTTGATAACGTCGCTGAAGGTACTGAATTAGCTGCTGAAGCA
+TCTGAACGAACTACTGAGTCTATCAAGACTCTTACTGGCGTAGCGTCAACAATCAGCGAC
+AAATTAAGTAAACTCGCTTCGATGCTCGAGTCGAAGGTTCAGGCTGTGGAGCAAAAAGTA
+CAAGAATCTGGTGCCTCAGCTTCAACTGGGCTGTCAGTGATAGAAGATAAGCTTCCAGAT
+CCTGATGAGCCTTTCTTTCCACCTGTCCCTCAGGAACCCGAGAACAACAAGAAAGATCAA
+AAGAAAGATGATAAGAAACCTACCGATATGTTAGGTGACTTGCTGAAGACTACGAAGGGC
+GGATTTAAAGCTACGATATCAATCACTGATAAAATATCGTCTATGCTTTTCAAATACACC
+GTAACAGCATTAGCTGAAGCTGCTAAAATGGCTGCTATGCTATTTGCATTAGTATTAGGC
+ATAGATTTACTTCGTATTCATTTTAAGTATTGGACTGATAAATTCATGAGTAACTTCGAT
+GAATTCAGTGCTGAAGCTGGTGAATGGGGTGGACTGCTTCAATCAATTTTTGGAATGTTA
+GGAGATATTAAAAAGTTCTGGGAAGCTGGAGACTGGAGTGGATTAGCAGTAGCTATTGTC
+AAAGGATTAGCTGATGTGATTTACAACCTGAGCGAAATAATGTCTTTGGGAATTTCAAAG
+ATATCTGCTTCTATACTCGATGCACTTGGCTTTGAAAATGCAGCAACTACTATTCGTGGT
+TCAGCACTAGAAGGATTCCAGGAACGCACTGGTAATTCATTGTCTGAAGATGATCAAAAA
+GCTTTGGCTAAATATCAGAGTAAGCGTATTGAAGAAGGTCCTGGAATTATTGATAAAGCT
+GGCGAATTTAAAACTCGTGCATTTGATTGGGTACTAGGAAGAGAGAATAAAATCGATTCT
+ACACAAGCATCTGACCGTGATCAAGAGACTCAGAATCTTAAAGCAATGGCTCCTGAAAAA
+CGCGAAGAAACACTGATCAAACAAAACGAAGCTCGTGCAGCTGTTCAGCGTTTAGAAAAA
+TATATTGGTGATGTTGATCCAGAGAATCCAACTAATATGCAATCTTTAGAGAAGGCATAT
+AACAGTGCCAAAAAGTCTATTAGTGATTCTGCTATAAGTGATCAACCAGCTACTAAAAAG
+GAACTCGATAAAAGATTCCAACGAGTAGAATCCAAGTATCAGAAGCTCAAAGAAGATAAC
+ACTCCGAAGCCTGCGGCTCCAGCTACTTCGGAAGATAATCAACGAGTTCAAAATATTCAA
+AAAGCTGAAAATGCTAAAGAGCAATCTAAAAAATCAACCGGTGATATGAATGTTGCTAAC
+ACTCAGGTTAATAACGTAAATAATAGTAAGACTATTCACCAGGTTCAAACAGTCACGGCT
+ACTCCAGCTCCTGGAGTATTCGGGGCAACAGGAGTTAATTAA
+>2706ea76-172a-48c1-b940-eb603996f082 (mRNA) 6 residues [Merlin:5011-6066 - strand] [cds] name=cds-not-under-exon
+CTTTAA
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/export/out.vcf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/export/out.vcf Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,5 @@
+##fileformat=VCFv4.2
+##fileDate=20191025XX
+##source=.
+##reference=/home/apollo_shared_dir/org2/seq/genome.fasta
+#CHROM POS ID REF ALT QUAL FILTER INFO
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/export/pep.fa
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/export/pep.fa Mon Dec 02 05:44:41 2019 -0500
[
@@ -0,0 +1,29 @@
+>ff2fe902-7bab-431c-be82-30ed072915d1 (mRNA) 229 residues [Merlin:2-691 + strand] [peptide] name=Unknown
+RLDKGTLLYRGQKLDLPTFEHNAENKLFYFRNYVSTSLKPLIFGEFGRMFMALDDDTTIY
+TAETPDDYNRFANPEDIIDIGATQKDSFDDNNNDGTSINIGKQVNLGFVISGAENVRVIV
+PGSLTEYPEEAEVILPRGTLLKINKITTQVDKRSNKFMVEGSIVPPSEQIDESVEIYDGD
+LFMETGEVVKLSGFMQFVNESAYDEEQNQMAAEILSGFLDIDDMPRKFR
+>f2e1909a-1d40-4a49-a67b-5fe2afdc4957 (mRNA) 2 residues [Merlin:752-1039 + strand] [peptide] name=Unknown
+KF
+>12fe0db6-c8e1-4bc9-b594-87c92c6c9669 (mRNA) 35 residues [Merlin:1067-2011 - strand] [peptide] name=Unknown
+HLNYHCRYSTAGKKVWCIEISYWSNEQSCCSVFIR
+>58fc8255-95ed-4417-a373-238f826810ac (mRNA) 351 residues [Merlin:2011-3066 - strand] [peptide] name=Unknown
+MSIKVRELDDKTDALISGVKTSAGQSSQSAKIKSTITAQYPSERSAGNDTSGSLRVHDLY
+KNGLLFTAYDMNSRTTGDMRSMRLGEMKRTANSVVKSITGTNTNKVDKIPVVNILLPRSK
+SDVESVSHKFNDVGDSLISRGGGTATGVLSNVASTAVFGGLESLTQGLMADHNEQIYNTA
+RSMYGGADNRTKVFTWDLTPRSVQDLIAIIEIYEYFNYYSYGETGTSTYAKEVKSQLDEW
+YKSTFLDTLTPDEANKNDTVFEKITSFLSNVIVVSNPTVWFVRNFGTTSKFDGRAEVFGP
+CQIQSIRFDKTPNGNFNGLAIAPNLPSTFTLEITMREILTLNRASVYAEGF
+>c009dd7a-3284-4e7f-9ee1-3b56e2598e07 (mRNA) 553 residues [Merlin:3066-4796 - strand] [peptide] name=multiexongene
+MKSENMSTMRRRKVIADSKGERDAASTASDQVDSLELIGLKLDDVQSANELVAEVIEEKG
+NNLIDSVDNVAEGTELAAEASERTTESIKTLTGVASTISDKLSKLASMLESKVQAVEQKV
+QESGASASTGLSVIEDKLPDPDEPFFPPVPQEPENNKKDQKKDDKKPTDMLGDLLKTTKG
+GFKATISITDKISSMLFKYTVTALAEAAKMAAMLFALVLGIDLLRIHFKYWTDKFMSNFD
+EFSAEAGEWGGLLQSIFGMLGDIKKFWEAGDWSGLAVAIVKGLADVIYNLSEIMSLGISK
+ISASILDALGFENAATTIRGSALEGFQERTGNSLSEDDQKALAKYQSKRIEEGPGIIDKA
+GEFKTRAFDWVLGRENKIDSTQASDRDQETQNLKAMAPEKREETLIKQNEARAAVQRLEK
+YIGDVDPENPTNMQSLEKAYNSAKKSISDSAISDQPATKKELDKRFQRVESKYQKLKEDN
+TPKPAAPATSEDNQRVQNIQKAENAKEQSKKSTGDMNVANTQVNNVNNSKTIHQVQTVTA
+TPAPGVFGATGVN
+>2706ea76-172a-48c1-b940-eb603996f082 (mRNA) 1 residues [Merlin:5011-6066 - strand] [peptide] name=cds-not-under-exon
+L
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/good-model.gff3
--- a/test-data/good-model.gff3 Mon Jul 29 10:09:19 2019 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
b
@@ -1,7 +0,0 @@
-##gff-version 3
-##sequence-region Maroon_JMcDermott 1 14805
-Maroon_JMcDermott feature gene 14488 14805 . + . ID=707c88b7-36d1-44e3-93e6-d1d4f1219d57;Name=gene_26;date_creation=2016-02-17;date_last_modified=2016-02-17;owner=jmc_texas%40tamu.edu
-Maroon_JMcDermott feature mRNA 14488 14805 . + . ID=8760695d-b88c-41c0-857b-540e6db81fe8;Name=gene_26-00001;Parent=707c88b7-36d1-44e3-93e6-d1d4f1219d57;date_creation=2016-02-17;date_last_modified=2016-02-17;owner=jmc_texas%40tamu.edu
-Maroon_JMcDermott feature CDS 14707 14805 . + 0 ID=94abf796-4c8d-45f4-916b-4d279616565e;Name=94abf796-4c8d-45f4-916b-4d279616565e-CDS;Parent=8760695d-b88c-41c0-857b-540e6db81fe8
-Maroon_JMcDermott feature exon 14497 14805 . + . ID=d2ebd8d0-6558-4674-a38f-346f88256340;Name=d2ebd8d0-6558-4674-a38f-346f88256340-exon;Parent=8760695d-b88c-41c0-857b-540e6db81fe8
-Maroon_JMcDermott feature Shine_Dalgarno_sequence 14488 14491 . + . ID=2e4119f9-3220-4502-8ddd-4821c872e0d6;Name=2e4119f9-3220-4502-8ddd-4821c872e0d6-exon;Parent=8760695d-b88c-41c0-857b-540e6db81fe8
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/load_gff3/output.tsv
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/load_gff3/output.tsv Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,7 @@
+# Feature ID Apollo ID Success Messages
+Merlin_1 a036ab4f-512d-45e3-b19e-1fe83984a185 success
+Merlin_2 4a3f5c6b-03fc-43d1-8d6d-1a7075931cc6 success
+Merlin_3 de819682-eb71-4b98-a532-032d59354b95 success
+Merlin_4 423ca5cc-d570-4ae8-8527-6a52e0a6862b success
+Merlin_5 f1b5327d-79ca-40f0-b4b3-90ea03d79a56 success
+Merlin_42 3629a7fe-03bb-420d-85d3-f23e55430abd success
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/merlin.gff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/merlin.gff Mon Dec 02 05:44:41 2019 -0500
b
@@ -0,0 +1,28 @@
+##gff-version 3
+##sequence-region Merlin 1 172788
+Merlin GeneMark.hmm gene 2 691 -856.563659 + . ID=Merlin_1;seqid=Merlin
+Merlin GeneMark.hmm mRNA 2 691 . + . ID=Merlin_1_mRNA;Parent=Merlin_1;seqid=Merlin;color=#00ff00
+Merlin GeneMark.hmm exon 2 691 . + . ID=Merlin_1_exon;Parent=Merlin_1_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 2 691 . + 0 ID=Merlin_1_CDS;Parent=Merlin_1_exon;seqid=Merlin
+Merlin GeneMark.hmm gene 752 1039 -339.046618 + . ID=Merlin_2;seqid=Merlin
+Merlin GeneMark.hmm mRNA 752 1039 . + . ID=Merlin_2_mRNA;Parent=Merlin_2;seqid=Merlin;Name=mrna-name
+Merlin GeneMark.hmm exon 752 1039 . + . ID=Merlin_2_exon;Parent=Merlin_2_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 852 939 . + 0 ID=Merlin_2_CDS;Parent=Merlin_2_exon;seqid=Merlin
+Merlin GeneMark.hmm gene 1067 2011 -1229.683915 - . ID=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm mRNA 1067 2011 . - . ID=Merlin_3_mRNA;Parent=Merlin_3;seqid=Merlin
+Merlin GeneMark.hmm exon 1067 2011 . - . ID=Merlin_3_exon;Parent=Merlin_3_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 1367 1811 . - 0 ID=Merlin_3_CDS;Parent=Merlin_3_exon;seqid=Merlin
+Merlin GeneMark.hmm gene 2011 3066 -1335.034872 - . ID=Merlin_4;seqid=Merlin
+Merlin GeneMark.hmm mRNA 2011 3066 . - . ID=Merlin_4_mRNA;Parent=Merlin_4;seqid=Merlin
+Merlin GeneMark.hmm exon 2011 3066 . - . ID=Merlin_4_exon;Parent=Merlin_4_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 2011 3066 . - 0 ID=Merlin_4_CDS;Parent=Merlin_4_exon;seqid=Merlin
+Merlin GeneMark.hmm gene 3066 4796 -2177.374893 - . ID=Merlin_5;seqid=Merlin;Name=multiexongene
+Merlin GeneMark.hmm mRNA 3066 4796 . - . ID=Merlin_5_mRNA;Parent=Merlin_5;seqid=Merlin
+Merlin GeneMark.hmm exon 3066 4296 . - . ID=Merlin_5_exon;Parent=Merlin_5_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 3066 4296 . - 0 ID=Merlin_5_CDS;Parent=Merlin_5_exon;seqid=Merlin
+Merlin GeneMark.hmm exon 4366 4796 . - . ID=Merlin_5_exon2;Parent=Merlin_5_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 4366 4796 . - 0 ID=Merlin_5_CDS2;Parent=Merlin_5_exon2;seqid=Merlin
+Merlin GeneMark.hmm gene 5011 6066 -1335.034872 - . ID=Merlin_42;seqid=Merlin;Name=cds-not-under-exon
+Merlin GeneMark.hmm mRNA 5011 6066 . - . ID=Merlin_42_mRNA;Parent=Merlin_42;seqid=Merlin
+Merlin GeneMark.hmm exon 5011 6066 . - . ID=Merlin_42_exon;Parent=Merlin_42_mRNA;seqid=Merlin
+Merlin GeneMark.hmm CDS 5011 6066 . - 0 ID=Merlin_42_CDS;Parent=Merlin_42_mRNA;seqid=Merlin
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 test-data/org_remote.tar.gz
b
Binary file test-data/org_remote.tar.gz has changed
b
diff -r 2adc3aa47d15 -r df0e4eb2dfa5 webapollo.py
--- a/webapollo.py Mon Jul 29 10:09:19 2019 -0400
+++ b/webapollo.py Mon Dec 02 05:44:41 2019 -0500
[
b'@@ -5,25 +5,16 @@\n import json\n import logging\n import os\n-import random\n import time\n from abc import abstractmethod\n \n-from BCBio import GFF\n-\n-from Bio import SeqIO\n-\n import requests\n \n from six.moves.builtins import next\n from six.moves.builtins import object\n-from six.moves.builtins import str\n-\n \n-try:\n-    import StringIO as io\n-except BaseException:\n-    import io\n+import yaml\n+\n logging.getLogger("requests").setLevel(logging.CRITICAL)\n log = logging.getLogger()\n \n@@ -431,38 +422,6 @@\n     parser.add_argument(\'--seq_raw\', nargs=\'*\', help=\'Sequence Names\')\n \n \n-def GuessOrg(args, wa):\n-    if args.org_json:\n-        orgs = [x.get(\'commonName\', None)\n-                for x in json.load(args.org_json)]\n-        orgs = [x for x in orgs if x is not None]\n-        return orgs\n-    elif args.org_raw:\n-        org = args.org_raw.strip()\n-        if len(org) > 0:\n-            return [org]\n-        else:\n-            raise Exception("Organism Common Name not provided")\n-    elif args.org_id:\n-        return [wa.organisms.findOrganismById(args.org_id).get(\'commonName\', None)]\n-    else:\n-        raise Exception("Organism Common Name not provided")\n-\n-\n-def GuessCn(args, wa):\n-    org = GuessOrg(args, wa)\n-    seqs = []\n-    if args.seq_fasta:\n-        # If we have a fasta, pull all rec ids from that.\n-        for rec in SeqIO.parse(args.seq_fasta, \'fasta\'):\n-            seqs.append(rec.id)\n-    elif args.seq_raw:\n-        # Otherwise raw list.\n-        seqs = [x.strip() for x in args.seq_raw if len(x.strip()) > 0]\n-\n-    return org, seqs\n-\n-\n def AssertUser(user_list):\n     if len(user_list) == 0:\n         raise UnknownUserException()\n@@ -472,50 +431,29 @@\n         raise Exception("Too many users!")\n \n \n-def AssertAdmin(user):\n-    if user.role == \'ADMIN\':\n-        return True\n-    else:\n-        raise Exception("User is not an administrator. Permission denied")\n-\n-\n-def PermissionCheck(user, org_cn, permission_type):\n-    return any(org["organism"] == org_cn and permission_type in org["permissions"] for org in user.organismPermissions)\n-\n-\n-def PasswordGenerator(length):\n-    chars = list(\'qwrtpsdfghjklzxcvbnm\')\n-    return \'\'.join(random.choice(chars) for _ in range(length))\n-\n-\n-def IsRemoteUser():\n-    if \'GALAXY_WEBAPOLLO_REMOTE_USER\' not in os.environ:\n-        return False\n-    value = os.environ[\'GALAXY_WEBAPOLLO_REMOTE_USER\']\n-    if value.lower() in (\'true\', \'t\', \'1\'):\n-        return True\n-    else:\n-        return False\n-\n-\n class WebApolloInstance(object):\n \n-    def __init__(self, url, username, password):\n-        self.apollo_url = url\n-        self.username = username\n-        self.password = password\n+    def __init__(self):\n+\n+        if \'ARROW_GLOBAL_CONFIG_PATH\' in os.environ:\n \n-        self.annotations = AnnotationsClient(self)\n+            with open(os.environ[\'ARROW_GLOBAL_CONFIG_PATH\'], \'r\') as config:\n+                conf = yaml.safe_load(config)\n+                try:\n+                    instance_name = conf[\'__default\']\n+                except KeyError:\n+                    raise Exception("Unknown Apollo instance and no __default provided")\n+                self.apollo_url = conf[instance_name][\'url\']\n+                self.username = conf[instance_name][\'username\']\n+                self.password = conf[instance_name][\'password\']\n+        else:\n+            self.apollo_url = os.environ[\'GALAXY_WEBAPOLLO_URL\']\n+            self.username = os.environ[\'GALAXY_WEBAPOLLO_USER\']\n+            self.password = os.environ[\'GALAXY_WEBAPOLLO_PASSWORD\']\n+\n         self.groups = GroupsClient(self)\n-        self.io = IOClient(self)\n         self.organisms = OrganismsClient(self)\n         self.users = UsersClient(self)\n-        self.metrics = MetricsClient(self)\n-        self.bio = RemoteRecord(self)\n-        self.status = StatusClient(self)\n-        self.canned_comments = CannedCommentsClient(self)\n-        self.canned_keys = CannedKeysClient(self)\n-        self.canned_values = CannedValuesClient(self)\n \n     def '..b'   # Key for cached data\n     cacheKey = \'groups-\' + email\n@@ -1601,11 +658,7 @@\n \n def galaxy_list_orgs(trans, *args, **kwargs):\n     email = trans.get_user().email\n-    wa = WebApolloInstance(\n-        os.environ[\'GALAXY_WEBAPOLLO_URL\'],\n-        os.environ[\'GALAXY_WEBAPOLLO_USER\'],\n-        os.environ[\'GALAXY_WEBAPOLLO_PASSWORD\']\n-    )\n+    wa = WebApolloInstance()\n     try:\n         gx_user = wa.requireUser(email)\n     except UnknownUserException:\n@@ -1635,53 +688,6 @@\n     return orgs\n \n \n-def galaxy_list_users(trans, *args, **kwargs):\n-    email = trans.get_user().email\n-    wa = WebApolloInstance(\n-        os.environ[\'GALAXY_WEBAPOLLO_URL\'],\n-        os.environ[\'GALAXY_WEBAPOLLO_USER\'],\n-        os.environ[\'GALAXY_WEBAPOLLO_PASSWORD\']\n-    )\n-    # Assert that the email exists in apollo\n-    try:\n-        gx_user = wa.requireUser(email)\n-    except UnknownUserException:\n-        return []\n-\n-    # Key for cached data\n-    cacheKey = \'users-\' + email\n-    # We don\'t want to trust "if key in cache" because between asking and fetch\n-    # it might through key error.\n-    if cacheKey not in cache:\n-        # However if it ISN\'T there, we know we\'re safe to fetch + put in\n-        # there.\n-        data = _galaxy_list_users(wa, gx_user, *args, **kwargs)\n-        cache[cacheKey] = data\n-        return data\n-    try:\n-        # The cache key may or may not be in the cache at this point, it\n-        # /likely/ is. However we take no chances that it wasn\'t evicted between\n-        # when we checked above and now, so we reference the object from the\n-        # cache in preparation to return.\n-        data = cache[cacheKey]\n-        return data\n-    except KeyError:\n-        # If access fails due to eviction, we will fail over and can ensure that\n-        # data is inserted.\n-        data = _galaxy_list_users(wa, gx_user, *args, **kwargs)\n-        cache[cacheKey] = data\n-        return data\n-\n-\n-def _galaxy_list_users(wa, gx_user, *args, **kwargs):\n-    # Fetch the users.\n-    user_data = []\n-    for user in wa.users.loadUsers():\n-        # Reformat\n-        user_data.append((user.username, user.username, False))\n-    return user_data\n-\n-\n # This is all for implementing the command line interface for testing.\n class obj(object):\n     pass\n@@ -1698,45 +704,14 @@\n         return o\n \n \n-def retry(closure, sleep=1, limit=5):\n-    """\n-    Apollo has the bad habit of returning 500 errors if you call APIs\n-    too quickly, largely because of the unholy things that happen in\n-    grails.\n-\n-    To deal with the fact that we cannot send an addComments call too\n-    quickly after a createFeature call, we have this function that will\n-    keep calling a closure until it works.\n-    """\n-    count = 0\n-    while True:\n-        count += 1\n-\n-        if count >= limit:\n-            return False\n-        try:\n-            # Try calling it\n-            closure()\n-            # If successful, exit\n-            return True\n-        except Exception as e:\n-            log.info(str(e)[0:100])\n-            time.sleep(sleep)\n-\n-\n if __name__ == \'__main__\':\n     parser = argparse.ArgumentParser(description=\'Test access to apollo server\')\n     parser.add_argument(\'email\', help=\'Email of user to test\')\n-    parser.add_argument(\'--action\', choices=[\'org\', \'group\', \'users\'], default=\'org\', help=\'Data set to test, fetch a list of groups or users known to the requesting user.\')\n+    parser.add_argument(\'--action\', choices=[\'org\', \'group\'], default=\'org\', help=\'Data set to test, fetch a list of groups or orgs known to the requesting user.\')\n     args = parser.parse_args()\n \n     trans = fakeTrans(args.email)\n     if args.action == \'org\':\n-        for f in galaxy_list_orgs(trans):\n-            print(f)\n+        print(galaxy_list_orgs(trans))\n     elif args.action == \'group\':\n-        for f in galaxy_list_groups(trans):\n-            print(f)\n-    else:\n-        for f in galaxy_list_users(trans):\n-            print(f)\n+        print(galaxy_list_groups(trans))\n'