Skip to content
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

[SVCS-86] Add Papaya Renderer for Dicom and NifTi Files #265

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open

[SVCS-86] Add Papaya Renderer for Dicom and NifTi Files #265

wants to merge 6 commits into from

Conversation

TomBaxter
Copy link
Member

@TomBaxter TomBaxter commented Jun 16, 2017

Purpose:

Create renderer for NifTI images. (.nii)

Collateral

Supports .nii.gz (NifTi files are commonly saved with .gz)
Supports .dcm (DICOM images)

Changes:

Create papaya renderer in /mfr/extensions/papaya
Relies on https://github.com/rii-mango/Papaya
Copies file to render to /mfr/extensions/papaya/static/data to make available to papaya.js
NiFTI files are often saved as .nii.gz by convention. I've added a facility to handle file extensions with an additional extension, such as compression.
At the beginning of each render files older then 5 minutes will be deleted.
Added a test.

Side effects

Some rendered file data will temporarily exist in mfr/extensions/papaya/static/data

Notes

I created PR for our use case...
rii-mango/Papaya#101
Which was accepted as of Papaya release build-1430
Use papaya.js and papaya.css from /Papaya-build-1430/release/current/standard/

We should keep an eye on this project...
https://github.com/FNNDSC/ami
We may want to switch to it in the future.

Tickets

https://openscience.atlassian.net/browse/SVCS-86

@TomBaxter TomBaxter changed the title [WIP] Add papaya renderer for nifti files. [RFR] [SVCS-86] Add papaya renderer for nifti files. Jun 28, 2017
Copy link
Contributor

@cslzchen cslzchen left a comment

Choose a reason for hiding this comment

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

@TomBaxter A few thoughts and suggestions, thanks.

  1. The papaya.js is super huge. Is there a way that it is loaded as a package or at least from a script tag which retrieves the content from a trusted third party domain or maybe our CDN domain (still in progress I think) that holds all the scripts/resources. Similar for the papaya.css though it is small. Update: it seems that including JS locally is how the way we built the MFR at the beginning. In the future we will have a package manager for JS. For now, it looks good.

  2. The project you mentioned now support Nifti1but still not .nii.gz or the .dcm. Is this worth trying?

  3. Formfr/extensions/papaya/static/data, does the temporary files only exist during file rendering? When are they cleaned? Don't want this to take up server memory.

@cslzchen cslzchen changed the title [RFR] [SVCS-86] Add papaya renderer for nifti files. [SVCS-86] Add Papaya Renderer for NifTi Files Oct 12, 2017
@TomBaxter TomBaxter changed the title [SVCS-86] Add Papaya Renderer for NifTi Files [SVCS-86] Add Papaya Renderer for Dicom and NifTi Files Oct 17, 2017
@TomBaxter
Copy link
Member Author

TomBaxter commented Oct 17, 2017

@cslzchen

  1. OK
  2. I don't think so. The Dicom files are the files that are in demand.
  3. The temporary files are removed at the beginning of each run of the renderer.

Copy link
Contributor

@cslzchen cslzchen left a comment

Choose a reason for hiding this comment

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

First pass done 🎆 with a few questions and suggestions. Back to you @TomBaxter .


def test_render_papaya(self, renderer, metadata, assets_url):
body = renderer.render()
print(body)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

return PapayaRenderer(metadata, file_path, url, assets_url, export_url)


class TestPapayaRenderer:
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we expand the tests to cover at least valid and invalid files:

  • Valid files
    • If there are any potential version issues/differences, we should include them as well.
  • Invalid/Corrupted files that may throw exceptions during opening, parsing, rendering, e.t.c.
    • We should be able to handle exceptions and return a relevant error message.

This applies to all three types. (Dicom, Compressed and Uncompressed NifTi).

Copy link
Member Author

Choose a reason for hiding this comment

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

Added tests for other two file extensions. However, not that interesting as this only tests the python rendering of the HTML. I don't believe there is a way to test the javascript from pytest. Therefore, didn't bother adding an Invalid/Corrupted test.

Copy link
Contributor

Choose a reason for hiding this comment

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

You are right. This is the render instead of the exporter. No need for the invalid files.

for data_file in os.listdir(self.data_dir):
if data_file == '.gitignore':
continue
if (time.time() - os.path.getctime(self.data_dir + data_file)) >= self.data_old:
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this a general util method for checking file time expiration for MFR in general?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

# Ignore everything in this directory
*
# Except this file
!.gitignore
Copy link
Contributor

Choose a reason for hiding this comment

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

We should ignore the directory and all its sub directories and contents instead of having such a .gitignore. In this way, no need to check:

if data_file == '.gitignore':
    continue

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure what you're getting at here. In any case, the .gitignore was for my convenience while developing. Removing it.

Copy link
Contributor

Choose a reason for hiding this comment

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

For example, here is a directory /repo/level_1/level_2/level_3/. If you want to ignore all files in level_3/, instead of having a level3/.gitignore you can use a level2/.gitignore or even a repo level one that ignores everything in the directory level3/.

Copy link
Member Author

Choose a reason for hiding this comment

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

Travis failed, which reminded me of why I had the .gitignore. In addition to it being handy during development, I also need it to create and check in the empty directory mfr/extensions/papaya/static/data/

Copy link
Contributor

@cslzchen cslzchen Nov 7, 2017

Choose a reason for hiding this comment

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

👍 I will locally test it again today before sending this to PCR.

class PapayaRenderer(extension.BaseRenderer):

data_dir = settings.DATA_DIR
data_old = settings.DATA_OLD
Copy link
Contributor

Choose a reason for hiding this comment

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

How about data_exp and DATA_EXP for expiration?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, OLD doesn't really fit. But EXP doesn't either. Went with TTL (Time To Live).

]).get_template('viewer.mako')

def render(self):
self.remove_old_files()
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean the temporary files for rendering will get stuck here all the time? Each time users try to render a file, the old ones gets removed but new ones are created.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that is correct.

Copy link
Contributor

@cslzchen cslzchen Nov 6, 2017

Choose a reason for hiding this comment

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

Not sure how much this will impact prod memory. MFR and WB pods constantly run out of space though. I will leave this for Phase 2 Review.

@@ -0,0 +1 @@
.papaya{width:90%;height:90%;margin:25px auto;background-color:black;font-family:sans-serif}.papaya:before{position:relative;content:"Papaya requires JavaScript...";display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif}.papaya-fullscreen{height:100%}.papaya-toolbar{text-align:left;box-sizing:content-box;position:relative}.papaya-toolbar ul{margin:0;list-style:none}.papaya-toolbar input[type=file]{text-align:right;display:none}.papaya-kiosk-controls{position:relative;margin:5px auto;list-style:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.papaya-kiosk-controls ul{list-style:none}.papaya-kiosk-controls button{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray}.papaya-control-increment{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;line-height:16px;box-sizing:border-box;font-family:"Courier New",Courier,monospace}.papaya-main-increment{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;font-family:"Courier New",Courier,monospace;background-color:lightgray;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;box-sizing:border-box;outline:0}.papaya-main-decrement{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;width:25px;text-align:center;font-family:"Courier New",Courier,monospace;background-color:lightgray;vertical-align:middle;padding:0;margin-left:auto;margin-right:auto;box-sizing:border-box;outline:0}.papaya-main-swap{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-main-goto-center{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-main-goto-origin{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;font-size:14px;height:25px;background-color:lightgray;outline:0}.papaya-slider-slice{padding:0 5px;display:inline}.papaya-slider-slice span{font-size:14px;font-family:sans-serif;vertical-align:middle}.papaya-slider-slice button{-webkit-appearance:none;border-radius:0;-webkit-border-radius:0;vertical-align:middle;font-size:14px;height:25px;background-color:lightgray}.papaya-controlbar-label{color:#000}.papaya-menu{width:220px;background:#222;z-index:100;position:absolute;border:solid 2px darkgray;padding:4px;margin:0}.papaya-menu li{font-size:12px;font-family:sans-serif;padding:4px 2px;color:#b5cbd3;cursor:pointer;list-style-type:none}.papaya-menu-label{font-size:14px;font-family:sans-serif;font-weight:bold;padding:2px 8px;cursor:pointer;vertical-align:text-bottom}.papaya-menu-titlebar{font-size:16px;font-family:sans-serif;padding:3px 8px 0 8px;cursor:default;vertical-align:text-bottom;color:white}.papaya-menu-icon{margin-left:5px}.papaya-menu-icon img{box-sizing:content-box}.papaya-menu-hovering{background-color:#444}.papaya-menu-spacer{height:8px}.papaya-menu-unselectable{-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none;user-drag:none}.papaya-menu-button-hovering{background-color:#DDD}.papaya-menu-filechooser{cursor:pointer;width:200px;display:inline-block;font-weight:normal}.papaya-menu-input{width:38px;margin-right:5px;color:black}li .papaya-menu-slider{vertical-align:middle;text-align:center;display:inline;width:120px;padding:0;margin:0}.papaya-dialog{min-width:400px;max-width:500px;height:500px;background:#222;position:absolute;z-index:100;border:solid 2px darkgray;padding:6px;font-size:14px;font-family:sans-serif;color:#b5cbd3;box-sizing:content-box;line-height:1.45}.papaya-dialog-content{margin:20px;height:415px;color:#dedede;overflow:auto;-ms-overflow-style:-ms-autohiding-scrollbar}.papaya-dialog-content-nowrap{white-space:nowrap}.papaya-dialog-content table{margin:0 auto}.papaya-dialog-content-label{text-align:right;padding:5px;color:#b5cbd3}.papaya-dialog-content-control{text-align:left;padding:5px}.papaya-dialog-content-help{text-align:right;padding:5px;color:lightgray;font-size:12px}.papaya-dialog-title{color:#b5cbd3;font-weight:bold;font-size:16px}.papaya-dialog-button{text-align:right;box-sizing:content-box;height:22px}.papaya-dialog-button button{box-sizing:content-box;color:black;font-size:11px}.papaya-dialog-background{position:fixed;top:0;left:0;background-color:#fff;width:100%;height:100%;opacity:.5}.papaya-dialog-stopscroll{height:100%;overflow:hidden}.checkForJS{width:90%;height:90%;margin:25px auto;background-color:black}.checkForJS:before{position:relative;content:"Papaya requires JavaScript...";display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif;text-align:center}.papaya-utils-unsupported{width:90%;height:90%;margin:25px auto;background-color:black}.papaya-utils-unsupported-message{position:relative;display:block;top:45%;color:red;margin:0 auto;font-size:18px;font-family:sans-serif;text-align:center}.papaya-viewer{line-height:1;font-family:sans-serif}.papaya-viewer div,.papaya-viewer canvas{margin:0;padding:0;border:0;font:inherit;font-size:100%;vertical-align:baseline;font-family:sans-serif}.papaya-viewer canvas{cursor:crosshair}
Copy link
Contributor

Choose a reason for hiding this comment

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

Add an empty line at the end of the file.

Copy link
Member Author

Choose a reason for hiding this comment

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

This file was copied straight from GitHub. I'm not knowledgeable about CSS, are you sure that is the right thing to do?

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure. It is GitHub that complains. No need to change.
screen shot 2017-11-06 at 4 34 55 pm

@@ -0,0 +1,2105 @@
var PAPAYA_BUILD_NUM="1430",papayaLoadableImages=[];
Copy link
Contributor

Choose a reason for hiding this comment

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

There are several different version of released code. Is this the smallest file that covers our need. (e.g. If their minimal version has what we need, we can use that one (1K+) instead of this (2K+).

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that is a question for product team. I demoed, and they appeared to like the added functionality.

@coveralls
Copy link

coveralls commented Nov 7, 2017

Coverage Status

Coverage increased (+0.6%) to 64.458% when pulling e723f4c on TomBaxter:feature/svcs-86 into ee122ff on CenterForOpenScience:develop.

Add customization to papaya library to disallow opening of new files from user desktop.

Consulted with Product Team. They determined that it would be confusing
and possibly dangerous to allow opening of files from user desktop, when
they might confuse it with the WaterButler repository.

Used a custom built papaya.js built on

https://github.com/TomBaxter/Papaya/tree/feature/noNewFiles

I have sent them a PR, hopefully they bite.

rii-mango/Papaya#101
@cslzchen
Copy link
Contributor

There is an "entrypoints" test that needs to be updated if you add new file types. Don't worry about it and I will have it along with my PR.

cslzchen added a commit to cslzchen/modular-file-renderer that referenced this pull request Nov 17, 2017
…cs-86

[SVCS-86] Add Papaya Renderer for Dicom and NifTi Files
@coveralls
Copy link

coveralls commented Nov 20, 2017

Coverage Status

Coverage increased (+0.5%) to 68.47% when pulling 6937fee on TomBaxter:feature/svcs-86 into 8bb2dd4 on CenterForOpenScience:develop.

@coveralls
Copy link

coveralls commented Nov 21, 2017

Coverage Status

Coverage increased (+0.7%) to 68.726% when pulling c834abf on TomBaxter:feature/svcs-86 into 8bb2dd4 on CenterForOpenScience:develop.

Copy link
Contributor

@cslzchen cslzchen left a comment

Choose a reason for hiding this comment

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

Looks good and works as expected. 🎆 🎆 Move to PCR.

@felliott @TomBaxter
There is one issue for Phase 2 on removing old files.

Temporary files are generated during rendering. It never gets deleted automatically. The solution in this PR is to remove old files in the temp directory at the beginning of each rendering. Here is a few concerns:

  • There is always old files there.
  • If more than one person try to render a file (and both try to clean the old files), only one of them will grab the lock while others hanging? Not able to tigger this locally but might be an issue on staging (less likely) and prod (likely).

Suggestions: we schedule a periodic task in celery to clean them?

@TomBaxter
Copy link
Member Author

Keep in mind that the files MFR downloads get named with a UUID, so overlap is extremely unlikely.

@TomBaxter
Copy link
Member Author

After discussing with @cslzchen , I understand his concern is that if two renderers try to delete a file that one will error since the other would have already deleted the file. An idea for handling this could be to simply handle the OSError exception with a try/except/pass .

@@ -0,0 +1,7 @@
Currently using a custom built papaya.js with option to remove the ability to open new files from the users desktop.
Copy link
Member Author

Choose a reason for hiding this comment

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

TODO: Remove this file. PR was accepted and we are no longer using custom build.

Copy link
Member

Choose a reason for hiding this comment

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

🎉 Nicely done!

@felliott felliott mentioned this pull request Jan 25, 2018
Copy link
Contributor

@cslzchen cslzchen left a comment

Choose a reason for hiding this comment

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

As mentioned, the PR that customized the JS lib has been accepted. This ticket and PR should be updated to reflect the changes. Please rebase and fix conflicts along the way. h/t to @TomBaxter and I will take over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants