-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Import gff ui #16
Import gff ui #16
Conversation
@aruginkgo keep you in the loop. I added the import gff UI here if you want to learn how I added them since I remember at one point you were working on something similar. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great!
My comments point out some ideas for improvement, some consistency/style points, and some minor errors.
.gitignore
Outdated
@@ -64,4 +64,6 @@ test.db* | |||
ncbi/ | |||
|
|||
# compiled static files | |||
static/ | |||
src/edge/static/edge/assets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these lines do not need to be added here. Asset compilation has changed; all compiled assets that should be ignored now go in src/edge/static/edge/assets, the compiled assets are ignored in the other .gitignore file, src/.gitignore
(I know, this is confusing; i didn't set this up, I just tried not to break it and keep the boundaries consistent.
these three lines should be removed; my original line should not be added back, however. that was just something i forgot to remove from when i was trying something different.
also, feel free to remove src/edge/static/edge/edge.css
in your local tree you won't need it.
src/edge/static/edge/src/js/app.js
Outdated
var model = $parse(attrs.fileModel); | ||
var modelSetter = model.assign; | ||
|
||
element.bind('change', function(){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spaces after closing paren for anon funcs, as above; please make it consistent throughout with whatever the existing convention is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just use a regular ng-model
for this? is it because ngModel
doesn't allow you to actually assign to sub-attributes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is to get the file in the controller's scope so I can process them easily. I learned this from here. https://www.uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs/
Not sure if this is the best way to do but it works fine.
$scope.add_genome_error = undefined; | ||
$scope.addGenome = function(){ | ||
var file = $scope.gffFile; | ||
$scope.add_genome_error = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use camelCase
here for consistency; pretty much all JS has now moved to this convention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right! Fixed. i_have_too_much_love_for_snake_case. Ruby was my first love and it has a profound impact on my coding style.
$scope.add_genome_pending = undefined; | ||
$scope.add_genome_result = undefined; | ||
if (!file) { | ||
$scope.add_genome_error = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can do this with a single object literal: $scope.addGenomeError = { message: 'Need to choose GFF file' };
also, prefer single quotes for consistency
@@ -0,0 +1,10 @@ | |||
<header> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done. This is much cleaner!
src/edge/views.py
Outdated
response = HttpResponse(content_type='text/plain') | ||
response['Content-Disposition'] = "attachment; filename=\"g%s.gff\"" % genome_id | ||
io.to_gff_file(response) | ||
return response | ||
|
||
|
||
def genome_import(request): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should stick some REST validation around this, making sure it only gets called on POST
s, etc; you can do this with the @require_POST()
decorator or a class-based view that only implements the post
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good thoughts! It's actually @require_http_methods(["POST"]) https://docs.djangoproject.com/en/1.11/topics/http/decorators/
src/edge/views.py
Outdated
response = HttpResponse(content_type='text/plain') | ||
response['Content-Disposition'] = "attachment; filename=\"g%s.gff\"" % genome_id | ||
io.to_gff_file(response) | ||
return response | ||
|
||
|
||
def genome_import(request): | ||
import tempfile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless you have a great reason for doing otherwise, it's less confusing IMO to put all imports at the top of a file.
src/edge/views.py
Outdated
"id": g.id, | ||
"name": g.name, | ||
}) | ||
build_genome_blastdb.delay(g.id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should return the task id in the API, so that if someone wants to check on the status, they can
src/edge/views.py
Outdated
def genome_import(request): | ||
import tempfile | ||
res = { | ||
"imported_genomes": [], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently, if your code throws any errors in this, you'll just return a 500 status; that might be fine, but there may be some errors you want to catch and report in your API instead, in an 'error' field.
src/edge/views.py
Outdated
build_genome_blastdb.delay(g.id) | ||
return HttpResponse(json.dumps(res), content_type='application/json') | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there tests for other views like this? Might make sense to add one if there are; shouldn't be so bad; i'd just mock up the task and import_gff
, and make sure that both are called as expected based on the number of genomes that are submitted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add a test for sure.
- gunzip ecoli-mg1655.gff for easier use as an example - Update styling - Fix label for="gff_file" that needs input id='gff_file'
@myw could you take another look? I've resolved most of your comments! Thank you for the detailed review. Learned quite a few things! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some HTML cleanup and a better way to write the GFF file.
$scope.getBaseURL = function() { return '/edge/'; } | ||
$scope.addGenome = function(){ | ||
var file = $scope.gffFile; | ||
$scope.addGenomeStatus = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice. I like this approach
} | ||
$scope.addGenomeStatus.pending = true; | ||
var fd = new FormData(); | ||
var gff_name = $scope.genome.name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still wrong convention
</div> | ||
<div class="form-group"> | ||
<label for="gff_file">GFF File (GFF3 format):</label><br/> | ||
<input type="file" file-model="gffFile" id='gff_file'/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
html attributes should use double quotes; also, Ids typically come first
|
||
<div class="form-group"> | ||
<label for="genome_name">Genome Name:</label> | ||
<input id="genome_name", name=name, type="text" ng-model="genome.name" required /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attributes should not have commas between them, and "name"
should have quotes around it.
<label for="gff_file">GFF File (GFF3 format):</label><br/> | ||
<input type="file" file-model="gffFile" id='gff_file'/> | ||
</div> | ||
<button class="btn btn-primary", type="submit", ng-disabled="userForm.$invalid", ng-click="addGenome()">Import</button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no commas between attributes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Fixed. I misread your previous comments, literally oblivated not
|
||
<div class="well" ng-show="addGenomeStatus.results"> | ||
<span class="text-success" ng-repeat='genome in addGenomeStatus.results.imported_genomes'> | ||
Success: Added in Edge as <a ng-href="#/genomes/{{ genome.id }}">Genome {{ genome.id }}: {{ genome.name }}</a></span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
span tag alignment is still weird here
src/edge/views.py
Outdated
response = HttpResponse(content_type='text/plain') | ||
response['Content-Disposition'] = "attachment; filename=\"g%s.gff\"" % genome_id | ||
io.to_gff_file(response) | ||
return response | ||
|
||
|
||
@require_http_methods(["POST"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by convention, we stick with single quotes for non-docstrings, unless you need them for brevity when expressing string literals that contain single quotes, e.g. "I like to 'eat' foods"
src/edge/views.py
Outdated
} | ||
for name in request.FILES: | ||
with tempfile.NamedTemporaryFile(mode='rw+b', delete=False) as gff: | ||
gff.write(request.FILES.get(name).read()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using .read()
can cause OOM errors for large files. Since GFFs can be large, I suggest doing the django-recommended best-practice and using UploadedFile.chunks
. See the docs for an example.
src/edge/views.py
Outdated
res = { | ||
'imported_genomes': [], | ||
} | ||
for name in request.FILES: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is more a matter of taste, but I find it much easier to read code with period line breaks in it to separate "paragraphs" or "thoughts". In here, to increase legibility, I'd stick extra lines after the dict literal, and before the return
, and around each individual "component" of the for loop: the gff writing/deletion, the BLASTdb task creation, and the call to JsonResponse
.
@myw can you take another look? Much appreciated! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just the commas;
commas betweet html attributes are not valid html
|
||
<div class="form-group"> | ||
<label for="genomeName">Genome Name:</label> | ||
<input id="genomeName", name="name", type="text", ng-model="genome.name" required /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No commas in html attributes
@myw fixed. Another look? Thanks! |
All good. Ready for merge! Re: the commas; no worries. I figured that is exactly what happened as I saw that you added more. |
Surprisingly, the commas did not cause any problems in html rendering in chrome even though it's clearly not the w3 standard. Maybe chrome is just forgiving about these errors. |
Thanks for the thorough review @myw! |
Add UI for import gff as genome in the database. Feature includes upload form validation and importing status and link to the uploaded genome after importing is finished.