Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions qiita_pet/handlers/admin_processing_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from qiita_core.util import execute_as_transaction

from qiita_db.software import Software
from qiita_db.study import Study

from json import dumps

Expand Down Expand Up @@ -91,3 +92,40 @@ def get(self):

# return the json in compact form to save transmit size
self.write(dumps(results, separators=(',', ':')))


class SampleValidation(AdminProcessingJobBaseClass):
@coroutine
@execute_as_transaction
def get(self):
self._check_access()

self.render("sample_validation.html", input=True)

@execute_as_transaction
def post(self):

# Get user-inputted qiita id and sample names
qid = self.get_argument("qid")
snames = self.get_argument("snames").split()

# Stripping leading qiita id from sample names
# Example: 1.SKB1.640202 -> SKB1.640202
qsnames = list(Study(qid).sample_template)
for i, qsname in enumerate(qsnames):
if qsname.startswith(qid):
qsnames[i] = qsname.replace(f'{qid}.', "", 1)

# Remove blank samples from sample names
blank = [x for x in snames if x.lower().startswith('blank')]
snames = [x for x in snames if 'blank' not in x.lower()]

# Validate user's sample names against qiita study
qsnames = set(qsnames)
snames = set(snames)
matching = qsnames.intersection(snames)
missing = qsnames.difference(snames)
extra = snames.difference(qsnames)

self.render("sample_validation.html", input=False, matching=matching,
missing=missing, extra=extra, blank=blank)
65 changes: 65 additions & 0 deletions qiita_pet/templates/sample_validation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{% extends sitebase.html %}
{% block head %}
<style>
.column {
float: left;
width: 25%;
}

.row:after {
content: "";
display: table;
clear: both;
}
</style>
{% end %}
{% block content %}
<h1>Sample Validation</h1><br>
{% if input %}
<form action="{% raw qiita_config.portal_dir %}/admin/sample_validation/" method="post" id="sample_validation_form">
<label for="qid">Qiita id:</label><br>
<input type="text" id="qid" name="qid"><br>
<label for="snames">Sample names:</label><br>
<textarea id="sname" name="snames"></textarea><br><br>
<input type="submit" value="Submit">
</form>
{% else %}
<div class="row">
<div class="column">
<h2>Matching</h2>
<ul>
{% for sample in matching %}
<li>{{ sample }}</li>
{% end %}
</ul>
</div>
<div class="column">
<h2>Missing</h2>
<ul>
{% for sample in missing %}
<li>{{ sample }}</li>
{% end %}
</ul>
</div>
<div class="column">
<h2>Blank</h2>
<ul>
{% for sample in blank %}
<li>{{ sample }}</li>
{% end %}
</ul>
</div>
<div class="column">
<h2>Extra</h2>
<ul>
{% for sample in extra %}
<li>{{ sample }}</li>
{% end %}
</ul>
</div>
</div>
<form action="{% raw qiita_config.portal_dir %}/admin/sample_validation/" method="get" id="return_to_sample_validation_form">
<input type="submit" value="Validate more samples">
</form>
{% end %}
{% end %}
1 change: 1 addition & 0 deletions qiita_pet/templates/sitebase.html
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@
<li><a href="{% raw qiita_config.portal_dir %}/admin/error/">View Errors</a></li>
<li><a href="{% raw qiita_config.portal_dir %}/admin/approval/">View Studies awaiting approval</a></li>
<li><a href="{% raw qiita_config.portal_dir %}/admin/portals/studies/">Edit study portal connections</a></li>
<li><a href="{% raw qiita_config.portal_dir %}/admin/sample_validation/">Sample Validation</a></li>
{% end %}
<li><a href="{% raw qiita_config.portal_dir %}/admin/processing_jobs/">Processing Jobs</a></li>
{% else %}
Expand Down
26 changes: 26 additions & 0 deletions qiita_pet/test/test_admin_processing_job_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,31 @@ def test_get_missing_argument(self):
response.body.decode('ascii'))


class TestSampleValidation(BaseAdminTests):
def test_get(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned during the meeting, a good unittest should canvas the common things that might break your method/function. For example, calling post without one or both of the post_args, or giving a value for qid or snames that is obviously bad. This confirms that error-handling exists and is working properly.

Copy link
Contributor Author

@sarayupai sarayupai Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified unit test to also check error handling of post with invalid qid

response = self.get('/admin/sample_validation/')
self.assertEqual(response.code, 200)

def test_post(self):
# Check success
post_args = {
'qid': 1,
'snames': 'SKB1.640202 SKB2.640194 BLANK.1A BLANK.1B'
}
response = self.post('/admin/sample_validation/', post_args)
self.assertEqual(response.code, 200)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some coders will return 200 as long as the command executed without failure on the server-side. It's good to check the response.text and confirm it does not contain error messages and contains at least some string of text you're expecting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified unit test to check that the response body contains the inputted sample names

snames = ['SKB1.640202', 'SKB2.640194', 'BLANK.1A', 'BLANK.1B']
body = response.body.decode('ascii')
for name in snames:
self.assertIn(name, body)
# Check failure: invalid qiita id
post_args = {
'qid': 2,
'snames': 'SKB1.640202 SKB2.640194 BLANK.1A BLANK.1B'
}
response = self.post('/admin/sample_validation/', post_args)
self.assertEqual(response.code, 500)


if __name__ == "__main__":
main()
3 changes: 2 additions & 1 deletion qiita_pet/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
ChangeForgotPasswordHandler, ForgotPasswordHandler, UserProfileHandler,
UserMessagesHander, UserJobs)
from qiita_pet.handlers.admin_processing_job import (
AdminProcessingJob, AJAXAdminProcessingJobListing)
AdminProcessingJob, AJAXAdminProcessingJobListing, SampleValidation)
from qiita_pet.handlers.analysis_handlers import (
ListAnalysesHandler, AnalysisSummaryAJAX, SelectedSamplesHandler,
AnalysisDescriptionHandler, AnalysisGraphHandler, CreateAnalysisHandler,
Expand Down Expand Up @@ -133,6 +133,7 @@ def __init__(self):
(r"/admin/artifact/", ArtifactAdminAJAX),
(r"/admin/processing_jobs/", AdminProcessingJob),
(r"/admin/processing_jobs/list", AJAXAdminProcessingJobListing),
(r"/admin/sample_validation/", SampleValidation),
(r"/ebi_submission/(.*)", EBISubmitHandler),
# Study handlers
(r"/study/create/", StudyEditHandler),
Expand Down