Skip to content

Commit 9e1c1b5

Browse files
authored
Merge pull request #2282 from antgonza/initial-redbiom-code
Redbiom initial code
2 parents c808c63 + 079f4eb commit 9e1c1b5

19 files changed

+767
-133
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,6 @@ gg_13_8-*
5757

5858
# sphinx documentation
5959
qiita_pet/static/doc/
60+
61+
# webdis log
62+
webdis.log

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ install:
5353
- redbiom admin create-context --name "qiita-test" --description "qiita-test context"
5454
- redbiom admin load-sample-metadata --metadata `pwd`/qiita_db/support_files/test_data/templates/1_19700101-000000.txt
5555
- redbiom admin load-sample-metadata-search --metadata `pwd`/qiita_db/support_files/test_data/templates/1_19700101-000000.txt
56-
- redbiom admin load-sample-data --table `pwd`/qiita_db/support_files/test_data/processed_data/1_study_1001_closed_reference_otu_table.biom --context qiita-test
56+
- redbiom admin load-sample-data --table `pwd`/qiita_db/support_files/test_data/processed_data/1_study_1001_closed_reference_otu_table.biom --context qiita-test --tag 4
57+
- redbiom admin load-sample-data --table `pwd`/qiita_db/support_files/test_data/processed_data/1_study_1001_closed_reference_otu_table-for_redbiom_tests.biom --context qiita-test --tag 5
5758
- mkdir ~/.qiita_plugins
59+
- export REDBIOM_HOST=http://127.0.0.1:7379
5860
- cp $PWD/qiita_core/support_files/BIOM\ type_2.1.4.conf ~/.qiita_plugins
5961
before_script:
6062
# EBI, see the end of before_install about why this block is commented out

INSTALL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ redbiom admin scripts-writable
107107
redbiom admin create-context --name "qiita-test" --description "qiita-test context"
108108
redbiom admin load-sample-metadata --metadata ${qdbd}/support_files/test_data/templates/1_19700101-000000.txt
109109
redbiom admin load-sample-metadata-search --metadata ${qdbd}/support_files/test_data/templates/1_19700101-000000.txt
110-
redbiom admin load-sample-data --table ${qdbd}/support_files/test_data/processed_data/1_study_1001_closed_reference_otu_table.biom --context qiita-test
110+
redbiom admin load-sample-data --table ${qdbd}/support_files/test_data/processed_data/1_study_1001_closed_reference_otu_table.biom --context qiita-test --tag 1
111111
```
112112

113113
Install Qiita development version and its python dependencies

qiita_db/test/test_util.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,68 @@ def test_generate_study_list(self):
843843
obs_info = qdb.util.generate_study_list([1, 2, 3, 4], False)
844844
self.assertEqual(obs_info, exp_info)
845845

846+
# resetting to private and deleting the old study
847+
qdb.artifact.Artifact(4).visibility = 'private'
848+
qdb.study.Study.delete(new_study.id)
849+
850+
def test_generate_study_list_without_artifacts(self):
851+
# creating a new study to make sure that empty studies are also
852+
# returned
853+
info = {"timeseries_type_id": 1, "metadata_complete": True,
854+
"mixs_compliant": True, "number_samples_collected": 25,
855+
"number_samples_promised": 28, "study_alias": "TST",
856+
"study_description": "Some description of the study goes here",
857+
"study_abstract": "Some abstract goes here",
858+
"emp_person_id": qdb.study.StudyPerson(1),
859+
"principal_investigator_id": qdb.study.StudyPerson(1),
860+
"lab_person_id": qdb.study.StudyPerson(1)}
861+
new_study = qdb.study.Study.create(
862+
qdb.user.User('shared@foo.bar'), 'test_study_1', info=info)
863+
864+
exp_info = [
865+
{'status': 'private', 'study_title': (
866+
'Identification of the Microbiomes for Cannabis Soils'),
867+
'metadata_complete': True, 'publication_pid': [
868+
'123456', '7891011'], 'ebi_submission_status': 'submitted',
869+
'study_id': 1, 'ebi_study_accession': 'EBI123456-BB',
870+
'study_abstract': (
871+
'This is a preliminary study to examine the microbiota '
872+
'associated with the Cannabis plant. Soils samples from '
873+
'the bulk soil, soil associated with the roots, and the '
874+
'rhizosphere were extracted and the DNA sequenced. Roots '
875+
'from three independent plants of different strains were '
876+
'examined. These roots were obtained November 11, 2011 from '
877+
'plants that had been harvested in the summer. Future studies '
878+
'will attempt to analyze the soils and rhizospheres from the '
879+
'same location at different time points in the plant '
880+
'lifecycle.'), 'pi': ('PI_dude@foo.bar', 'PIDude'),
881+
'publication_doi': ['10.100/123456', '10.100/7891011'],
882+
'study_alias': 'Cannabis Soils', 'number_samples_collected': 27},
883+
{'status': 'sandbox', 'study_title': 'test_study_1',
884+
'metadata_complete': True, 'publication_pid': [],
885+
'ebi_submission_status': 'not submitted',
886+
'study_id': new_study.id, 'ebi_study_accession': None,
887+
'study_abstract': 'Some abstract goes here',
888+
'pi': ('lab_dude@foo.bar', 'LabDude'), 'publication_doi': [],
889+
'study_alias': 'TST', 'number_samples_collected': 0}]
890+
obs_info = qdb.util.generate_study_list_without_artifacts(
891+
[1, 2, 3, 4], True)
892+
self.assertEqual(obs_info, exp_info)
893+
894+
qdb.artifact.Artifact(4).visibility = 'public'
895+
exp_info[0]['status'] = 'public'
896+
obs_info = qdb.util.generate_study_list_without_artifacts(
897+
[1, 2, 3, 4], True)
898+
self.assertEqual(obs_info, exp_info)
899+
900+
obs_info = qdb.util.generate_study_list_without_artifacts(
901+
[1, 2, 3, 4], False)
902+
self.assertEqual(obs_info, exp_info)
903+
904+
# resetting to private and deleting the old study
905+
qdb.artifact.Artifact(4).visibility = 'private'
906+
qdb.study.Study.delete(new_study.id)
907+
846908
def test_get_artifacts_information(self):
847909
# we are gonna test that it ignores 1 and 2 cause they are not biom,
848910
# 4 has all information and 7 and 8 don't

qiita_db/util.py

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,24 +1310,86 @@ def generate_study_list(study_ids, public_only=False):
13101310
del info["shared_with_name"]
13111311
del info["shared_with_email"]
13121312

1313-
infolist.append({
1314-
'owner': info['owner'],
1315-
'study_alias': info['study_alias'],
1316-
'metadata_complete': info['metadata_complete'],
1317-
'publication_pid': info['publication_pid'],
1318-
'ebi_submission_status': info['ebi_submission_status'],
1319-
'shared': info['shared'],
1320-
'study_abstract': info['study_abstract'], 'pi': info['pi'],
1321-
'status': qdb.study.Study(info['study_id']).status,
1322-
'study_tags': info['study_tags'],
1323-
'publication_doi': info['publication_doi'],
1324-
'study_id': info['study_id'],
1325-
'ebi_study_accession': info['ebi_study_accession'],
1326-
'study_title': info['study_title'],
1327-
'number_samples_collected': info['number_samples_collected'],
1328-
'artifact_biom_ids': info['artifact_biom_ids']
1329-
})
1313+
info['status'] = qdb.study.Study(info['study_id']).status
1314+
infolist.append(info)
1315+
return infolist
1316+
1317+
1318+
def generate_study_list_without_artifacts(study_ids, public_only=False):
1319+
"""Get general study information without artifacts
1320+
1321+
Parameters
1322+
----------
1323+
study_ids : list of ints
1324+
The study ids to look for. Non-existing ids will be ignored
1325+
public_only : bool, optional
1326+
If true, return only public BIOM artifacts. Default: false.
1327+
1328+
Returns
1329+
-------
1330+
list of dict
1331+
The list of studies and their information
1332+
1333+
Notes
1334+
-----
1335+
The main select might look scary but it's pretty simple:
1336+
- We select the requiered fields from qiita.study and qiita.study_person
1337+
SELECT metadata_complete, study_abstract, study_id, study_alias,
1338+
study_title, ebi_study_accession, ebi_submission_status,
1339+
qiita.study_person.name AS pi_name,
1340+
qiita.study_person.email AS pi_email,
1341+
- the total number of samples collected by counting sample_ids
1342+
(SELECT COUNT(sample_id) FROM qiita.study_sample
1343+
WHERE study_id=qiita.study.study_id)
1344+
AS number_samples_collected]
1345+
- all the publications that belong to the study
1346+
(SELECT array_agg((publication, is_doi)))
1347+
FROM qiita.study_publication
1348+
WHERE study_id=qiita.study.study_id) AS publications
1349+
"""
1350+
with qdb.sql_connection.TRN:
1351+
sql = """
1352+
SELECT metadata_complete, study_abstract, study_id, study_alias,
1353+
study_title, ebi_study_accession, ebi_submission_status,
1354+
qiita.study_person.name AS pi_name,
1355+
qiita.study_person.email AS pi_email,
1356+
(SELECT COUNT(sample_id) FROM qiita.study_sample
1357+
WHERE study_id=qiita.study.study_id)
1358+
AS number_samples_collected,
1359+
(SELECT array_agg(row_to_json((publication, is_doi), true))
1360+
FROM qiita.study_publication
1361+
WHERE study_id=qiita.study.study_id) AS publications
1362+
FROM qiita.study
1363+
LEFT JOIN qiita.study_person ON (
1364+
study_person_id=principal_investigator_id)
1365+
WHERE study_id IN %s
1366+
ORDER BY study_id"""
1367+
qdb.sql_connection.TRN.add(sql, [tuple(study_ids)])
1368+
infolist = []
1369+
for info in qdb.sql_connection.TRN.execute_fetchindex():
1370+
info = dict(info)
1371+
1372+
# publication info
1373+
info['publication_doi'] = []
1374+
info['publication_pid'] = []
1375+
if info['publications'] is not None:
1376+
for p in info['publications']:
1377+
# f1-2 are the default names given
1378+
pub = p['f1']
1379+
is_doi = p['f2']
1380+
if is_doi:
1381+
info['publication_doi'].append(pub)
1382+
else:
1383+
info['publication_pid'].append(pub)
1384+
del info['publications']
1385+
1386+
# pi info
1387+
info["pi"] = (info['pi_email'], info['pi_name'])
1388+
del info["pi_email"]
1389+
del info["pi_name"]
13301390

1391+
info['status'] = qdb.study.Study(info['study_id']).status
1392+
infolist.append(info)
13311393
return infolist
13321394

13331395

qiita_pet/handlers/qiita_redbiom.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# -----------------------------------------------------------------------------
2+
# Copyright (c) 2014--, The Qiita Development Team.
3+
#
4+
# Distributed under the terms of the BSD 3-clause License.
5+
#
6+
# The full license is in the file LICENSE, distributed with this software.
7+
# -----------------------------------------------------------------------------
8+
9+
from requests import ConnectionError
10+
from collections import defaultdict
11+
import redbiom.summarize
12+
import redbiom.search
13+
import redbiom._requests
14+
import redbiom.util
15+
import redbiom.fetch
16+
from tornado.gen import coroutine, Task
17+
18+
from qiita_core.util import execute_as_transaction
19+
from qiita_db.util import generate_study_list_without_artifacts
20+
from qiita_db.study import Study
21+
22+
from .base_handlers import BaseHandler
23+
24+
25+
class RedbiomPublicSearch(BaseHandler):
26+
@execute_as_transaction
27+
def get(self, search):
28+
self.render('redbiom.html')
29+
30+
def _redbiom_metadata_search(self, query, contexts):
31+
study_artifacts = defaultdict(list)
32+
message = ''
33+
query = query.lower()
34+
try:
35+
samples = redbiom.search.metadata_full(query, False)
36+
except TypeError:
37+
message = (
38+
'Not a valid search: "%s", are you sure this is a '
39+
'valid metadata value?' % query)
40+
except ValueError:
41+
message = (
42+
'Not a valid search: "%s", your query is too small '
43+
'(too few letters), try a longer query' % query)
44+
if not message:
45+
sids = set([s.split('.', 1)[0] for s in samples])
46+
for s in sids:
47+
study_artifacts[s] = [a.id for a in Study(s).artifacts(
48+
artifact_type='BIOM')]
49+
50+
return message, study_artifacts
51+
52+
def _redbiom_feature_search(self, query, contexts):
53+
study_artifacts = defaultdict(list)
54+
query = [f for f in query.split(' ')]
55+
for ctx in contexts:
56+
for idx in redbiom.util.ids_from(query, True, 'feature', ctx):
57+
aid, sid = idx.split('_', 1)
58+
sid = sid.split('.', 1)[0]
59+
study_artifacts[sid].append(aid)
60+
61+
return '', study_artifacts
62+
63+
def _redbiom_taxon_search(self, query, contexts):
64+
study_artifacts = defaultdict(list)
65+
for ctx in contexts:
66+
# find the features with those taxonomies and then search
67+
# those features in the samples
68+
features = redbiom.fetch.taxon_descendents(ctx, query)
69+
for idx in redbiom.util.ids_from(features, True, 'feature',
70+
ctx):
71+
aid, sid = idx.split('_', 1)
72+
sid = sid.split('.', 1)[0]
73+
study_artifacts[sid].append(aid)
74+
75+
return '', study_artifacts
76+
77+
@execute_as_transaction
78+
def _redbiom_search(self, query, search_on, callback):
79+
search_f = {'metadata': self._redbiom_metadata_search,
80+
'feature': self._redbiom_feature_search,
81+
'taxon': self._redbiom_taxon_search}
82+
83+
message = ''
84+
results = []
85+
86+
try:
87+
df = redbiom.summarize.contexts()
88+
except ConnectionError:
89+
message = 'Redbiom is down - contact admin, thanks!'
90+
else:
91+
contexts = df.ContextName.values
92+
if search_on in search_f:
93+
message, study_artifacts = search_f[search_on](query, contexts)
94+
if not message:
95+
keys = study_artifacts.keys()
96+
if keys:
97+
results = generate_study_list_without_artifacts(
98+
study_artifacts.keys(), True)
99+
# inserting the artifact_biom_ids to the results
100+
for i in range(len(results)):
101+
results[i]['artifact_biom_ids'] = list(set(
102+
study_artifacts[str(results[i]['study_id'])]))
103+
else:
104+
message = "No samples where found! Try again ..."
105+
else:
106+
message = ('Incorrect search by: you can use metadata, '
107+
'features or taxon and you passed: %s' % search_on)
108+
109+
callback((results, message))
110+
111+
@coroutine
112+
@execute_as_transaction
113+
def post(self, search):
114+
search = self.get_argument('search')
115+
search_on = self.get_argument('search_on')
116+
117+
data, msg = yield Task(self._redbiom_search, search, search_on)
118+
119+
self.write({'status': 'success', 'message': msg, 'data': data})

0 commit comments

Comments
 (0)