histomicsui 1.4.7.dev44__tar.gz → 1.4.7.dev49__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.circleci/config.yml +1 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.git-blame-ignore-revs +2 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.pre-commit-config.yaml +10 -3
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/PKG-INFO +1 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/__init__.py +37 -11
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/handlers.py +16 -10
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/aperio.py +8 -5
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/case.py +11 -7
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/cohort.py +3 -2
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/image.py +18 -10
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/meta.py +14 -11
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/pathology.py +2 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/slide.py +8 -5
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/aperio.py +11 -11
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/hui_resource.py +13 -11
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/image_browse_resource.py +5 -4
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/system.py +24 -17
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/tcga.py +107 -98
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/app.js +15 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/PKG-INFO +1 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/SOURCES.txt +1 -1
- histomicsui-1.4.7.dev49/ruff.toml +69 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/datastore.py +1 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_hui_rest.py +17 -17
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_image_browse_endpoints.py +1 -1
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_tcga.py +122 -120
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_web_client.py +12 -12
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tox.ini +6 -2
- histomicsui-1.4.7.dev44/.travis.yml +0 -24
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.editorconfig +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.gitignore +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/LICENSE +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/MANIFEST.in +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/NOTICE +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/README.rst +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/codecov.yml +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/config_options.rst +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/controls.rst +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/difference.gif +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/intersect.gif +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/union.gif +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/xor.gif +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/constants.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/__init__.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/__init__.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/StyleCollection.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/UserCollection.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/confirmDialog.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editElement.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editRegionOfInterest.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editStyleGroups.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/metadataPlot.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/openAnnotatedImage.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/openImage.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/saveAnnotation.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/events.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/main.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/models/StyleModel.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/models/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/package.json +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/AnnotationSelector.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/DrawWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/FrameSelectorWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/MetadataPlot.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/MetadataWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/OverviewWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/RegionSelector.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/ZoomWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/router.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/routes.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/static/favicon.png +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/body/configView.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/body/image.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/editStyleGroups.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/openAnnotatedImage.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/saveAnnotation.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/header.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/headerAnalyses.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/headerImage.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/layout.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/annotationSelector.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/drawWidget.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/frameSelectorWidget.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/metadataPlot.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/metadataWidget.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/overviewWidget.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/regionSelector.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/zoomWidget.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/popover/annotationContextMenu.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/popover/annotationPopover.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/views/itemList.styl +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/body/configView.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/body/image.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/annotatedImageList.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/confirmDialog.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editElement.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editRegionOfInterest.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editStyleGroups.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/metadataPlot.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/openAnnotatedImage.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/openImage.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/saveAnnotation.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/header.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerAnalyses.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerImage.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerUser.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/layout.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/annotationSelector.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/drawWidget.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/drawWidgetElement.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/frameSelectorWidget.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/metadataPlot.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/metadataWidgetPanel.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/overviewWidget.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/panel.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/regionSelector.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/zoomWidget.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationContextMenu.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationPopover.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationPopoverMetadata.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/pixelmapContextMenu.pug +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/HierarchyWidget.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/View.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/ConfigView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/ImageView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/itemList.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/itemPage.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderAnalysesView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderImageView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderUserView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderView.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/AnnotationContextMenu.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/AnnotationPopover.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/PixelmapContextMenu.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/index.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/utils.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/ColorPickerInput.vue +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/EditHeatmapOrGridData.vue +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/EditHeatmapOrGridDataContainer.vue +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/webpack.helper.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/webroot.mako +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/dependency_links.txt +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/entry_points.txt +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/not-zip-safe +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/requires.txt +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/top_level.txt +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/requirements-dev.txt +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/setup.cfg +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/setup.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/__init__.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/girder_utilities.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/.histomicsui_config.yaml +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample.anot +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample.meta +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample_girder_id.anot +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/test_analysis_detection.xml +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/test_analysis_features.xml +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_handlers.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_load.py +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/.eslintrc +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/analysisSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/annotationSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/girderUISpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/huiSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/huiTest.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/itemSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/metadataPanelSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/metadataPlotSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/overviewPanelSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/panelLayoutSpec.js +0 -0
- {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/pixelmapCategorySpec.js +0 -0
|
@@ -11,3 +11,5 @@ b566911831095bb4c161e2161e2d1a33cf3f4f18
|
|
|
11
11
|
f1c2190ab04ab867c655b4217f807e9f567772c8
|
|
12
12
|
# PR 296: Use stylus-supremacy for linting and reformating stylus files
|
|
13
13
|
9475b89640a6de84788b79ba68d5ed9aeb1a9ff4
|
|
14
|
+
# PR 359: Apply ruff formatting and linting
|
|
15
|
+
97b21f031e4769043b2c3a464ea4cf8e9a60c219
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# See https://pre-commit.com/hooks.html for more hooks
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
-
rev: v4.
|
|
5
|
+
rev: v4.5.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: check-added-large-files
|
|
8
8
|
- id: check-ast
|
|
@@ -42,7 +42,7 @@ repos:
|
|
|
42
42
|
files: README.rst
|
|
43
43
|
name: rst-linter of README.rst
|
|
44
44
|
- repo: https://github.com/codespell-project/codespell
|
|
45
|
-
rev: v2.2.
|
|
45
|
+
rev: v2.2.6
|
|
46
46
|
hooks:
|
|
47
47
|
- id: codespell
|
|
48
48
|
args:
|
|
@@ -59,8 +59,15 @@ repos:
|
|
|
59
59
|
args:
|
|
60
60
|
- '--options'
|
|
61
61
|
- './histomicsui/web_client/package.json'
|
|
62
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
63
|
+
# Ruff version.
|
|
64
|
+
rev: v0.1.0
|
|
65
|
+
hooks:
|
|
66
|
+
- id: ruff
|
|
67
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
68
|
+
types_or: [python, pyi, jupyter]
|
|
62
69
|
- repo: https://github.com/asottile/pyupgrade
|
|
63
|
-
rev: v3.
|
|
70
|
+
rev: v3.15.0
|
|
64
71
|
hooks:
|
|
65
72
|
- id: pyupgrade
|
|
66
73
|
args:
|
|
@@ -19,6 +19,7 @@ import os
|
|
|
19
19
|
import re
|
|
20
20
|
from functools import wraps
|
|
21
21
|
|
|
22
|
+
import cherrypy
|
|
22
23
|
from bson import json_util
|
|
23
24
|
from girder import events, logger, plugin
|
|
24
25
|
from girder.api import access
|
|
@@ -30,6 +31,7 @@ from girder.models.file import File
|
|
|
30
31
|
from girder.models.folder import Folder
|
|
31
32
|
from girder.models.item import Item
|
|
32
33
|
from girder.models.setting import Setting
|
|
34
|
+
from girder.models.token import Token
|
|
33
35
|
from girder.settings import SettingDefault, SettingKey
|
|
34
36
|
from girder.utility import config
|
|
35
37
|
from girder.utility import path as path_util
|
|
@@ -56,7 +58,7 @@ except DistributionNotFound:
|
|
|
56
58
|
|
|
57
59
|
_template = os.path.join(
|
|
58
60
|
os.path.dirname(__file__),
|
|
59
|
-
'webroot.mako'
|
|
61
|
+
'webroot.mako',
|
|
60
62
|
)
|
|
61
63
|
|
|
62
64
|
|
|
@@ -153,29 +155,35 @@ def validateListOrJSON(doc):
|
|
|
153
155
|
})
|
|
154
156
|
def validateHistomicsUIColor(doc):
|
|
155
157
|
if not doc['value']:
|
|
156
|
-
|
|
158
|
+
msg = 'The banner color may not be empty'
|
|
159
|
+
raise ValidationException(msg, 'value')
|
|
157
160
|
elif not re.match(r'^#[0-9A-Fa-f]{6}$', doc['value']):
|
|
158
|
-
|
|
161
|
+
msg = 'The banner color must be a hex color triplet'
|
|
162
|
+
raise ValidationException(msg, 'value')
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
@setting_utilities.validator(PluginSettings.HUI_BRAND_NAME)
|
|
162
166
|
def validateHistomicsUIBrandName(doc):
|
|
163
167
|
if not doc['value']:
|
|
164
|
-
|
|
168
|
+
msg = 'The brand name may not be empty'
|
|
169
|
+
raise ValidationException(msg, 'value')
|
|
165
170
|
|
|
166
171
|
|
|
167
172
|
@setting_utilities.validator(PluginSettings.HUI_WEBROOT_PATH)
|
|
168
173
|
def validateHistomicsUIWebrootPath(doc):
|
|
169
174
|
if not doc['value']:
|
|
170
|
-
|
|
175
|
+
msg = 'The webroot path may not be empty'
|
|
176
|
+
raise ValidationException(msg, 'value')
|
|
171
177
|
if re.match(r'^girder$', doc['value']):
|
|
172
|
-
|
|
178
|
+
msg = 'The webroot path may not be "girder"'
|
|
179
|
+
raise ValidationException(msg, 'value')
|
|
173
180
|
|
|
174
181
|
|
|
175
182
|
@setting_utilities.validator(PluginSettings.HUI_ALTERNATE_WEBROOT_PATH)
|
|
176
183
|
def validateHistomicsUIAlternateWebrootPath(doc):
|
|
177
184
|
if re.match(r'(^,|)girder(,|$)', doc['value']):
|
|
178
|
-
|
|
185
|
+
msg = 'The alternate webroot path may not contain "girder"'
|
|
186
|
+
raise ValidationException(msg, 'value')
|
|
179
187
|
|
|
180
188
|
|
|
181
189
|
@setting_utilities.validator(PluginSettings.HUI_QUARANTINE_FOLDER)
|
|
@@ -195,14 +203,14 @@ SettingDefault.defaults.update({
|
|
|
195
203
|
PluginSettings.HUI_HELP_URL:
|
|
196
204
|
'https://github.com/DigitalSlideArchive/HistomicsUI/blob/master/docs/controls.rst',
|
|
197
205
|
PluginSettings.HUI_HELP_TOOLTIP: 'Mouse and keyboard controls',
|
|
198
|
-
PluginSettings.HUI_HELP_TEXT: 'Help'
|
|
206
|
+
PluginSettings.HUI_HELP_TEXT: 'Help',
|
|
199
207
|
})
|
|
200
208
|
|
|
201
209
|
|
|
202
210
|
@setting_utilities.validator({
|
|
203
211
|
PluginSettings.HUI_HELP_URL,
|
|
204
212
|
PluginSettings.HUI_HELP_TOOLTIP,
|
|
205
|
-
PluginSettings.HUI_HELP_TEXT
|
|
213
|
+
PluginSettings.HUI_HELP_TEXT,
|
|
206
214
|
})
|
|
207
215
|
def validateHistomicsUIHelp(doc):
|
|
208
216
|
pass
|
|
@@ -255,10 +263,27 @@ class WebrootHistomicsUI(Webroot):
|
|
|
255
263
|
'huiBannerColor': Setting().get(PluginSettings.HUI_BANNER_COLOR),
|
|
256
264
|
'huiHelpURL': Setting().get(PluginSettings.HUI_HELP_URL),
|
|
257
265
|
'huiHelpTooltip': Setting().get(PluginSettings.HUI_HELP_TOOLTIP),
|
|
258
|
-
'huiHelpText': Setting().get(PluginSettings.HUI_HELP_TEXT)
|
|
266
|
+
'huiHelpText': Setting().get(PluginSettings.HUI_HELP_TEXT),
|
|
259
267
|
})
|
|
260
268
|
return super()._renderHTML()
|
|
261
269
|
|
|
270
|
+
def GET(self, **params):
|
|
271
|
+
print(params)
|
|
272
|
+
if params.get('token'):
|
|
273
|
+
try:
|
|
274
|
+
token = Token().load(params['token'], force=True, objectId=False)
|
|
275
|
+
if token:
|
|
276
|
+
cookie = cherrypy.response.cookie
|
|
277
|
+
cookie['girderToken'] = str(token['_id'])
|
|
278
|
+
cookie['girderToken']['path'] = '/'
|
|
279
|
+
days = float(Setting().get(SettingKey.COOKIE_LIFETIME))
|
|
280
|
+
cookie['girderToken']['expires'] = int(days * 3600 * 24)
|
|
281
|
+
cookie['girderToken']['sameSite'] = 'None'
|
|
282
|
+
cookie['girderToken']['secure'] = True
|
|
283
|
+
except Exception:
|
|
284
|
+
pass
|
|
285
|
+
return self._renderHTML()
|
|
286
|
+
|
|
262
287
|
|
|
263
288
|
def restrict_downloads(info):
|
|
264
289
|
"""
|
|
@@ -308,8 +333,9 @@ def restrict_downloads(info):
|
|
|
308
333
|
def wrapped(*args, **kwargs):
|
|
309
334
|
if (not getCurrentToken() and len(args) >= 1 and
|
|
310
335
|
args[0] and args[0].get('size', 0) >= limit):
|
|
336
|
+
msg = 'You must be logged in or have a valid auth token.'
|
|
311
337
|
raise AccessException(
|
|
312
|
-
|
|
338
|
+
msg)
|
|
313
339
|
return fun(*args, **kwargs)
|
|
314
340
|
return wrapped
|
|
315
341
|
File().download = limitLengthDownload(
|
|
@@ -129,7 +129,7 @@ def process_annotations(event): # noqa
|
|
|
129
129
|
|
|
130
130
|
file = File().load(
|
|
131
131
|
event.info.get('file', {}).get('_id'),
|
|
132
|
-
level=AccessType.READ, user=user
|
|
132
|
+
level=AccessType.READ, user=user,
|
|
133
133
|
)
|
|
134
134
|
startTime = time.time()
|
|
135
135
|
|
|
@@ -139,7 +139,8 @@ def process_annotations(event): # noqa
|
|
|
139
139
|
try:
|
|
140
140
|
if file['size'] > int(large_image.config.getConfig(
|
|
141
141
|
'max_annotation_input_file_length', 1024 ** 3)):
|
|
142
|
-
|
|
142
|
+
msg = 'File is larger than will be read into memory.'
|
|
143
|
+
raise Exception(msg)
|
|
143
144
|
data = []
|
|
144
145
|
with File().open(file) as fptr:
|
|
145
146
|
while True:
|
|
@@ -189,12 +190,15 @@ def quarantine_item(item, user, makePlaceholder=True):
|
|
|
189
190
|
"""
|
|
190
191
|
folder = Setting().get(PluginSettings.HUI_QUARANTINE_FOLDER)
|
|
191
192
|
if not folder:
|
|
192
|
-
|
|
193
|
+
msg = 'The quarantine folder is not configured.'
|
|
194
|
+
raise RestException(msg)
|
|
193
195
|
folder = Folder().load(folder, force=True, exc=True)
|
|
194
196
|
if not folder:
|
|
195
|
-
|
|
197
|
+
msg = 'The quarantine folder does not exist.'
|
|
198
|
+
raise RestException(msg)
|
|
196
199
|
if str(folder['_id']) == str(item['folderId']):
|
|
197
|
-
|
|
200
|
+
msg = 'The item is already in the quarantine folder.'
|
|
201
|
+
raise RestException(msg)
|
|
198
202
|
originalFolder = Folder().load(item['folderId'], force=True)
|
|
199
203
|
quarantineInfo = {
|
|
200
204
|
'originalFolderId': item['folderId'],
|
|
@@ -202,7 +206,7 @@ def quarantine_item(item, user, makePlaceholder=True):
|
|
|
202
206
|
'originalBaseParentId': item['baseParentId'],
|
|
203
207
|
'originalUpdated': item['updated'],
|
|
204
208
|
'quarantineUserId': user['_id'],
|
|
205
|
-
'quarantineTime': datetime.datetime.now(datetime.timezone.utc)
|
|
209
|
+
'quarantineTime': datetime.datetime.now(datetime.timezone.utc),
|
|
206
210
|
}
|
|
207
211
|
item = Item().move(item, folder)
|
|
208
212
|
if makePlaceholder:
|
|
@@ -216,7 +220,7 @@ def quarantine_item(item, user, makePlaceholder=True):
|
|
|
216
220
|
if makePlaceholder:
|
|
217
221
|
placeholderInfo = {
|
|
218
222
|
'quarantined': True,
|
|
219
|
-
'quarantineTime': quarantineInfo['quarantineTime']
|
|
223
|
+
'quarantineTime': quarantineInfo['quarantineTime'],
|
|
220
224
|
}
|
|
221
225
|
placeholder.setdefault('meta', {})['quarantine'] = placeholderInfo
|
|
222
226
|
placeholder = Item().updateItem(placeholder)
|
|
@@ -232,10 +236,12 @@ def restore_quarantine_item(item, user):
|
|
|
232
236
|
:returns: the modified item.
|
|
233
237
|
"""
|
|
234
238
|
if not item.get('meta', {}).get('quarantine'):
|
|
235
|
-
|
|
239
|
+
msg = 'The item has no quarantine record.'
|
|
240
|
+
raise RestException(msg)
|
|
236
241
|
folder = Folder().load(item['meta']['quarantine']['originalFolderId'], force=True)
|
|
237
242
|
if not folder:
|
|
238
|
-
|
|
243
|
+
msg = 'The original folder is not accessible.'
|
|
244
|
+
raise RestException(msg)
|
|
239
245
|
if 'placeholderItemId' in item['meta']['quarantine']:
|
|
240
246
|
placeholder = Item().load(item['meta']['quarantine']['placeholderItemId'], force=True)
|
|
241
247
|
else:
|
|
@@ -256,7 +262,7 @@ def process_metadata(event):
|
|
|
256
262
|
return
|
|
257
263
|
file = File().load(
|
|
258
264
|
event.info.get('file', {}).get('_id'),
|
|
259
|
-
level=AccessType.READ, user=results['user']
|
|
265
|
+
level=AccessType.READ, user=results['user'],
|
|
260
266
|
)
|
|
261
267
|
|
|
262
268
|
if not file:
|
|
@@ -15,7 +15,7 @@ class Aperio(Item):
|
|
|
15
15
|
aperio_re = re.compile(
|
|
16
16
|
r'^(?P<barcode>(?P<case>' +
|
|
17
17
|
TCGAModel.case_re.pattern + r')[0-9a-z-]*)\.xml',
|
|
18
|
-
flags=re.I
|
|
18
|
+
flags=re.I,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
def initialize(self, **kwargs):
|
|
@@ -32,14 +32,16 @@ class Aperio(Item):
|
|
|
32
32
|
try:
|
|
33
33
|
Item().load(imageId, force=True)
|
|
34
34
|
except Exception:
|
|
35
|
+
msg = 'The item is not associated with a valid image.'
|
|
35
36
|
raise ValidationException(
|
|
36
|
-
|
|
37
|
+
msg,
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
files = Item().childFiles(doc)
|
|
40
41
|
if files.count() != 1:
|
|
42
|
+
msg = 'The annotation item must have exactly one file.'
|
|
41
43
|
raise ValidationException(
|
|
42
|
-
|
|
44
|
+
msg,
|
|
43
45
|
)
|
|
44
46
|
|
|
45
47
|
meta.setdefault('tag', None)
|
|
@@ -72,7 +74,7 @@ class Aperio(Item):
|
|
|
72
74
|
name = doc['name']
|
|
73
75
|
d = self.aperio_re.match(name).groupdict()
|
|
74
76
|
image = TCGAImage().findOne({
|
|
75
|
-
'tcga.barcode': d['barcode'].upper()
|
|
77
|
+
'tcga.barcode': d['barcode'].upper(),
|
|
76
78
|
})
|
|
77
79
|
self.importDocument(doc, image, **kwargs)
|
|
78
80
|
|
|
@@ -84,7 +86,8 @@ class Aperio(Item):
|
|
|
84
86
|
except ValidationException:
|
|
85
87
|
pass
|
|
86
88
|
else:
|
|
87
|
-
|
|
89
|
+
msg = 'Invalid model type'
|
|
90
|
+
raise ValidationException(msg)
|
|
88
91
|
|
|
89
92
|
def findAperio(self, image, tag=None, **kwargs):
|
|
90
93
|
"""Find Aperio annotations associated with the given image."""
|
|
@@ -9,24 +9,27 @@ class Case(TCGAModel, Folder):
|
|
|
9
9
|
|
|
10
10
|
TCGAType = 'case'
|
|
11
11
|
TCGAIndices = [
|
|
12
|
-
'tcga.label'
|
|
12
|
+
'tcga.label',
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
def validate(self, doc, **kwargs):
|
|
16
16
|
if doc.get('parentCollection') != 'folder':
|
|
17
|
+
msg = 'A Case model must be a child of a folder'
|
|
17
18
|
raise ValidationException(
|
|
18
|
-
|
|
19
|
+
msg,
|
|
19
20
|
)
|
|
20
21
|
super().validate(doc, **kwargs)
|
|
21
22
|
cohort = Cohort().load(
|
|
22
23
|
doc['parentId'], force=True)
|
|
23
24
|
if not cohort or self.getTCGAType(cohort) != 'cohort':
|
|
25
|
+
msg = 'A Case model must be a child of a cohort'
|
|
24
26
|
raise ValidationException(
|
|
25
|
-
|
|
27
|
+
msg,
|
|
26
28
|
)
|
|
27
29
|
if not self.case_re.match(self.getTCGA(doc).get('label', '')):
|
|
30
|
+
msg = 'Invalid label in TCGA metadata'
|
|
28
31
|
raise ValidationException(
|
|
29
|
-
|
|
32
|
+
msg,
|
|
30
33
|
)
|
|
31
34
|
return doc
|
|
32
35
|
|
|
@@ -35,11 +38,12 @@ class Case(TCGAModel, Folder):
|
|
|
35
38
|
|
|
36
39
|
recurse = kwargs.get('recurse', False)
|
|
37
40
|
parent = Cohort().load(
|
|
38
|
-
doc.get('parentId'), force=True
|
|
41
|
+
doc.get('parentId'), force=True,
|
|
39
42
|
)
|
|
40
43
|
if not parent:
|
|
44
|
+
msg = 'Invalid folder document'
|
|
41
45
|
raise ValidationException(
|
|
42
|
-
|
|
46
|
+
msg,
|
|
43
47
|
)
|
|
44
48
|
tcga = self.getTCGA(parent)
|
|
45
49
|
tcga['label'] = doc['name']
|
|
@@ -51,7 +55,7 @@ class Case(TCGAModel, Folder):
|
|
|
51
55
|
|
|
52
56
|
childModel = Slide()
|
|
53
57
|
children = Folder().childFolders(
|
|
54
|
-
doc, 'folder', user=kwargs.get('user')
|
|
58
|
+
doc, 'folder', user=kwargs.get('user'),
|
|
55
59
|
)
|
|
56
60
|
for child in children:
|
|
57
61
|
try:
|
|
@@ -11,8 +11,9 @@ class Cohort(TCGAModel, Folder):
|
|
|
11
11
|
def validate(self, doc, **kwargs):
|
|
12
12
|
super().validate(doc, **kwargs)
|
|
13
13
|
if doc['parentCollection'] != 'collection':
|
|
14
|
+
msg = 'A Cohort model must be a child of a collection'
|
|
14
15
|
raise ValidationException(
|
|
15
|
-
|
|
16
|
+
msg,
|
|
16
17
|
)
|
|
17
18
|
return doc
|
|
18
19
|
|
|
@@ -28,7 +29,7 @@ class Cohort(TCGAModel, Folder):
|
|
|
28
29
|
|
|
29
30
|
childModel = Case()
|
|
30
31
|
children = Folder().childFolders(
|
|
31
|
-
doc, 'folder', user=kwargs.get('user')
|
|
32
|
+
doc, 'folder', user=kwargs.get('user'),
|
|
32
33
|
)
|
|
33
34
|
for child in children:
|
|
34
35
|
try:
|
|
@@ -14,27 +14,32 @@ class Image(TCGAModel, Item):
|
|
|
14
14
|
def validate(self, doc, **kwargs):
|
|
15
15
|
super().validate(doc, **kwargs)
|
|
16
16
|
if 'largeImage' not in doc:
|
|
17
|
+
msg = 'An image item must be a "large_image"'
|
|
17
18
|
raise ValidationException(
|
|
18
|
-
|
|
19
|
+
msg,
|
|
19
20
|
)
|
|
20
21
|
slide = Slide().load(
|
|
21
22
|
doc['folderId'], force=True)
|
|
22
23
|
if not slide or self.getTCGAType(slide) != 'slide':
|
|
24
|
+
msg = 'An image must be a child of a slide'
|
|
23
25
|
raise ValidationException(
|
|
24
|
-
|
|
26
|
+
msg,
|
|
25
27
|
)
|
|
26
28
|
tcga = self.getTCGA(doc)
|
|
27
29
|
if not self.case_re.match(tcga.get('case', '')):
|
|
30
|
+
msg = 'Invalid case name in TCGA metadata'
|
|
28
31
|
raise ValidationException(
|
|
29
|
-
|
|
32
|
+
msg,
|
|
30
33
|
)
|
|
31
34
|
if not self.barcode_re.match(tcga.get('barcode', '')):
|
|
35
|
+
msg = 'Invalid barcode in TCGA metadata'
|
|
32
36
|
raise ValidationException(
|
|
33
|
-
|
|
37
|
+
msg,
|
|
34
38
|
)
|
|
35
39
|
if not self.uuid_re.match(tcga.get('uuid', '')):
|
|
40
|
+
msg = 'Invalid uuid in TCGA metadata'
|
|
36
41
|
raise ValidationException(
|
|
37
|
-
|
|
42
|
+
msg,
|
|
38
43
|
)
|
|
39
44
|
|
|
40
45
|
return doc
|
|
@@ -46,11 +51,12 @@ class Image(TCGAModel, Item):
|
|
|
46
51
|
try:
|
|
47
52
|
return ImageItem.createImageItem(
|
|
48
53
|
doc, file,
|
|
49
|
-
user=user, token=token, createJob=False
|
|
54
|
+
user=user, token=token, createJob=False,
|
|
50
55
|
)
|
|
51
56
|
except Exception:
|
|
57
|
+
msg = 'Could not generate a large_image item'
|
|
52
58
|
raise ValidationException(
|
|
53
|
-
|
|
59
|
+
msg,
|
|
54
60
|
)
|
|
55
61
|
|
|
56
62
|
def _findImageFile(self, doc):
|
|
@@ -64,18 +70,20 @@ class Image(TCGAModel, Item):
|
|
|
64
70
|
token = kwargs.get('token')
|
|
65
71
|
fileId = self._findImageFile(doc)
|
|
66
72
|
if fileId is None:
|
|
73
|
+
msg = 'Could not find a TCGA slide in item'
|
|
67
74
|
raise ValidationException(
|
|
68
|
-
|
|
75
|
+
msg,
|
|
69
76
|
)
|
|
70
77
|
self._setLargeImage(doc, fileId, user, token)
|
|
71
78
|
|
|
72
79
|
name = doc['name']
|
|
73
80
|
parent = Slide().load(
|
|
74
|
-
doc.get('folderId'), force=True
|
|
81
|
+
doc.get('folderId'), force=True,
|
|
75
82
|
)
|
|
76
83
|
if not parent:
|
|
84
|
+
msg = 'Invalid item document'
|
|
77
85
|
raise ValidationException(
|
|
78
|
-
|
|
86
|
+
msg,
|
|
79
87
|
)
|
|
80
88
|
tcga = self.getTCGA(parent)
|
|
81
89
|
tcga.update(self.parseImage(name))
|
|
@@ -58,13 +58,13 @@ class TCGAModel:
|
|
|
58
58
|
#: Matches valid uuid's
|
|
59
59
|
uuid_re = re.compile(
|
|
60
60
|
r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
|
|
61
|
-
flags=re.I
|
|
61
|
+
flags=re.I,
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
#: Matches valid tcga barcodes
|
|
65
65
|
barcode_re = re.compile(
|
|
66
66
|
case_re.pattern + r'[0-9a-z-]*',
|
|
67
|
-
flags=re.I
|
|
67
|
+
flags=re.I,
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
#: Parses tcga slide image file names
|
|
@@ -72,7 +72,7 @@ class TCGAModel:
|
|
|
72
72
|
r'^(?P<barcode>(?P<case>' +
|
|
73
73
|
case_re.pattern + r')[0-9a-z-]*)\.' +
|
|
74
74
|
r'(?P<uuid>' + uuid_re.pattern + r')\.svs$',
|
|
75
|
-
flags=re.I
|
|
75
|
+
flags=re.I,
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
#: Parses tcga pathology report file names
|
|
@@ -80,7 +80,7 @@ class TCGAModel:
|
|
|
80
80
|
r'^(?P<case>' + case_re.pattern +
|
|
81
81
|
r')\.(?P<uuid>' + uuid_re.pattern +
|
|
82
82
|
r')\.pdf$',
|
|
83
|
-
flags=re.I
|
|
83
|
+
flags=re.I,
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
def initialize(self, **kwargs):
|
|
@@ -149,14 +149,15 @@ class TCGAModel:
|
|
|
149
149
|
def getTCGACollection(self):
|
|
150
150
|
"""Get the unique TCGA collection from the settings collection."""
|
|
151
151
|
tcga = Setting().get(
|
|
152
|
-
TCGACollectionSettingKey
|
|
152
|
+
TCGACollectionSettingKey,
|
|
153
153
|
)
|
|
154
154
|
if tcga is None:
|
|
155
|
+
msg = 'TCGA collection id not initialized in settings'
|
|
155
156
|
raise Exception(
|
|
156
|
-
|
|
157
|
+
msg,
|
|
157
158
|
)
|
|
158
159
|
return Collection().load(
|
|
159
|
-
tcga, force=True
|
|
160
|
+
tcga, force=True,
|
|
160
161
|
)
|
|
161
162
|
|
|
162
163
|
def __upper(self, obj, key):
|
|
@@ -170,7 +171,8 @@ class TCGAModel:
|
|
|
170
171
|
def _parse(self, name, regex):
|
|
171
172
|
m = regex.match(name)
|
|
172
173
|
if m is None:
|
|
173
|
-
|
|
174
|
+
msg = 'Invalid name'
|
|
175
|
+
raise ValidationException(msg)
|
|
174
176
|
d = m.groupdict()
|
|
175
177
|
self.__lower(d, 'uuid')
|
|
176
178
|
self.__upper(d, 'barcode')
|
|
@@ -190,7 +192,7 @@ class TCGAModel:
|
|
|
190
192
|
"""Set the mime type of a file document."""
|
|
191
193
|
oldType = doc.get('mimeType')
|
|
192
194
|
newType = mimetypes.guess_type(
|
|
193
|
-
doc.get('name', '')
|
|
195
|
+
doc.get('name', ''),
|
|
194
196
|
)[0]
|
|
195
197
|
doc['mimeType'] = newType
|
|
196
198
|
return newType != oldType
|
|
@@ -218,8 +220,9 @@ class TCGAModel:
|
|
|
218
220
|
return doc
|
|
219
221
|
except ValidationException:
|
|
220
222
|
pass
|
|
223
|
+
msg = 'Invalid document id provided'
|
|
221
224
|
raise ValidationException(
|
|
222
|
-
|
|
225
|
+
msg,
|
|
223
226
|
)
|
|
224
227
|
|
|
225
228
|
def iterateItems(self, doc, **kwargs):
|
|
@@ -248,7 +251,7 @@ class TCGAModel:
|
|
|
248
251
|
parentType = parentType.lower()
|
|
249
252
|
q = {
|
|
250
253
|
'parentId': parent['_id'],
|
|
251
|
-
'parentCollection': parentType
|
|
254
|
+
'parentCollection': parentType,
|
|
252
255
|
}
|
|
253
256
|
q.update(filters or {})
|
|
254
257
|
return self.find(q, sort=sort, limit=limit, offset=offset)
|
|
@@ -11,15 +11,17 @@ class Slide(TCGAModel, Folder):
|
|
|
11
11
|
|
|
12
12
|
def validate(self, doc, **kwargs):
|
|
13
13
|
if not doc.get('parentCollection') == 'folder':
|
|
14
|
+
msg = 'A Slide model must be a child of a folder'
|
|
14
15
|
raise ValidationException(
|
|
15
|
-
|
|
16
|
+
msg,
|
|
16
17
|
)
|
|
17
18
|
super().validate(doc, **kwargs)
|
|
18
19
|
case = Case().load(
|
|
19
20
|
doc['parentId'], force=True)
|
|
20
21
|
if not case or self.getTCGAType(case) != 'case':
|
|
22
|
+
msg = 'A Slide model must be a child of a case'
|
|
21
23
|
raise ValidationException(
|
|
22
|
-
|
|
24
|
+
msg,
|
|
23
25
|
)
|
|
24
26
|
return doc
|
|
25
27
|
|
|
@@ -28,11 +30,12 @@ class Slide(TCGAModel, Folder):
|
|
|
28
30
|
|
|
29
31
|
recurse = kwargs.get('recurse', False)
|
|
30
32
|
parent = Case().load(
|
|
31
|
-
doc.get('parentId'), force=True
|
|
33
|
+
doc.get('parentId'), force=True,
|
|
32
34
|
)
|
|
33
35
|
if not parent:
|
|
36
|
+
msg = 'Invalid folder document'
|
|
34
37
|
raise ValidationException(
|
|
35
|
-
|
|
38
|
+
msg,
|
|
36
39
|
)
|
|
37
40
|
tcga = self.getTCGA(parent)
|
|
38
41
|
tcga.pop('meta', None)
|
|
@@ -43,7 +46,7 @@ class Slide(TCGAModel, Folder):
|
|
|
43
46
|
|
|
44
47
|
childModel = Image()
|
|
45
48
|
children = Folder().childItems(
|
|
46
|
-
doc, user=kwargs.get('user')
|
|
49
|
+
doc, user=kwargs.get('user'),
|
|
47
50
|
)
|
|
48
51
|
for child in children:
|
|
49
52
|
try:
|