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.
Files changed (178) hide show
  1. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.circleci/config.yml +1 -1
  2. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.git-blame-ignore-revs +2 -0
  3. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.pre-commit-config.yaml +10 -3
  4. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/PKG-INFO +1 -1
  5. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/__init__.py +37 -11
  6. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/handlers.py +16 -10
  7. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/aperio.py +8 -5
  8. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/case.py +11 -7
  9. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/cohort.py +3 -2
  10. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/image.py +18 -10
  11. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/meta.py +14 -11
  12. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/pathology.py +2 -1
  13. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/slide.py +8 -5
  14. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/aperio.py +11 -11
  15. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/hui_resource.py +13 -11
  16. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/image_browse_resource.py +5 -4
  17. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/system.py +24 -17
  18. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/tcga.py +107 -98
  19. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/app.js +15 -1
  20. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/PKG-INFO +1 -1
  21. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/SOURCES.txt +1 -1
  22. histomicsui-1.4.7.dev49/ruff.toml +69 -0
  23. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/datastore.py +1 -1
  24. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_hui_rest.py +17 -17
  25. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_image_browse_endpoints.py +1 -1
  26. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_tcga.py +122 -120
  27. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_web_client.py +12 -12
  28. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tox.ini +6 -2
  29. histomicsui-1.4.7.dev44/.travis.yml +0 -24
  30. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.editorconfig +0 -0
  31. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/.gitignore +0 -0
  32. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/LICENSE +0 -0
  33. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/MANIFEST.in +0 -0
  34. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/NOTICE +0 -0
  35. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/README.rst +0 -0
  36. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/codecov.yml +0 -0
  37. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/config_options.rst +0 -0
  38. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/controls.rst +0 -0
  39. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/difference.gif +0 -0
  40. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/intersect.gif +0 -0
  41. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/union.gif +0 -0
  42. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/docs/images/xor.gif +0 -0
  43. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/constants.py +0 -0
  44. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/models/__init__.py +0 -0
  45. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/rest/__init__.py +0 -0
  46. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/StyleCollection.js +0 -0
  47. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/UserCollection.js +0 -0
  48. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/collections/index.js +0 -0
  49. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/confirmDialog.js +0 -0
  50. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editElement.js +0 -0
  51. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editRegionOfInterest.js +0 -0
  52. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/editStyleGroups.js +0 -0
  53. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/index.js +0 -0
  54. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/metadataPlot.js +0 -0
  55. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/openAnnotatedImage.js +0 -0
  56. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/openImage.js +0 -0
  57. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/dialogs/saveAnnotation.js +0 -0
  58. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/events.js +0 -0
  59. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/index.js +0 -0
  60. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/main.js +0 -0
  61. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/models/StyleModel.js +0 -0
  62. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/models/index.js +0 -0
  63. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/package.json +0 -0
  64. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/AnnotationSelector.js +0 -0
  65. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/DrawWidget.js +0 -0
  66. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/FrameSelectorWidget.js +0 -0
  67. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/MetadataPlot.js +0 -0
  68. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/MetadataWidget.js +0 -0
  69. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/OverviewWidget.js +0 -0
  70. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/RegionSelector.js +0 -0
  71. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/ZoomWidget.js +0 -0
  72. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/panels/index.js +0 -0
  73. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/router.js +0 -0
  74. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/routes.js +0 -0
  75. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/static/favicon.png +0 -0
  76. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/body/configView.styl +0 -0
  77. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/body/image.styl +0 -0
  78. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/editStyleGroups.styl +0 -0
  79. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/openAnnotatedImage.styl +0 -0
  80. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/dialogs/saveAnnotation.styl +0 -0
  81. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/header.styl +0 -0
  82. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/headerAnalyses.styl +0 -0
  83. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/headerImage.styl +0 -0
  84. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/layout/layout.styl +0 -0
  85. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/annotationSelector.styl +0 -0
  86. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/drawWidget.styl +0 -0
  87. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/frameSelectorWidget.styl +0 -0
  88. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/metadataPlot.styl +0 -0
  89. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/metadataWidget.styl +0 -0
  90. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/overviewWidget.styl +0 -0
  91. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/regionSelector.styl +0 -0
  92. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/panels/zoomWidget.styl +0 -0
  93. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/popover/annotationContextMenu.styl +0 -0
  94. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/popover/annotationPopover.styl +0 -0
  95. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/stylesheets/views/itemList.styl +0 -0
  96. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/body/configView.pug +0 -0
  97. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/body/image.pug +0 -0
  98. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/annotatedImageList.pug +0 -0
  99. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/confirmDialog.pug +0 -0
  100. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editElement.pug +0 -0
  101. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editRegionOfInterest.pug +0 -0
  102. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/editStyleGroups.pug +0 -0
  103. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/metadataPlot.pug +0 -0
  104. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/openAnnotatedImage.pug +0 -0
  105. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/openImage.pug +0 -0
  106. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/dialogs/saveAnnotation.pug +0 -0
  107. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/header.pug +0 -0
  108. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerAnalyses.pug +0 -0
  109. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerImage.pug +0 -0
  110. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/headerUser.pug +0 -0
  111. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/layout/layout.pug +0 -0
  112. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/annotationSelector.pug +0 -0
  113. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/drawWidget.pug +0 -0
  114. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/drawWidgetElement.pug +0 -0
  115. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/frameSelectorWidget.pug +0 -0
  116. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/metadataPlot.pug +0 -0
  117. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/metadataWidgetPanel.pug +0 -0
  118. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/overviewWidget.pug +0 -0
  119. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/panel.pug +0 -0
  120. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/regionSelector.pug +0 -0
  121. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/panels/zoomWidget.pug +0 -0
  122. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationContextMenu.pug +0 -0
  123. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationPopover.pug +0 -0
  124. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/annotationPopoverMetadata.pug +0 -0
  125. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/templates/popover/pixelmapContextMenu.pug +0 -0
  126. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/HierarchyWidget.js +0 -0
  127. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/View.js +0 -0
  128. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/ConfigView.js +0 -0
  129. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/ImageView.js +0 -0
  130. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/body/index.js +0 -0
  131. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/index.js +0 -0
  132. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/itemList.js +0 -0
  133. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/itemPage.js +0 -0
  134. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderAnalysesView.js +0 -0
  135. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderImageView.js +0 -0
  136. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderUserView.js +0 -0
  137. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/HeaderView.js +0 -0
  138. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/layout/index.js +0 -0
  139. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/AnnotationContextMenu.js +0 -0
  140. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/AnnotationPopover.js +0 -0
  141. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/PixelmapContextMenu.js +0 -0
  142. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/popover/index.js +0 -0
  143. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/views/utils.js +0 -0
  144. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/ColorPickerInput.vue +0 -0
  145. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/EditHeatmapOrGridData.vue +0 -0
  146. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/vue/components/EditHeatmapOrGridDataContainer.vue +0 -0
  147. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/web_client/webpack.helper.js +0 -0
  148. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui/webroot.mako +0 -0
  149. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/dependency_links.txt +0 -0
  150. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/entry_points.txt +0 -0
  151. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/not-zip-safe +0 -0
  152. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/requires.txt +0 -0
  153. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/histomicsui.egg-info/top_level.txt +0 -0
  154. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/requirements-dev.txt +0 -0
  155. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/setup.cfg +0 -0
  156. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/setup.py +0 -0
  157. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/__init__.py +0 -0
  158. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/girder_utilities.py +0 -0
  159. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/.histomicsui_config.yaml +0 -0
  160. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample.anot +0 -0
  161. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample.meta +0 -0
  162. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/sample_girder_id.anot +0 -0
  163. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/test_analysis_detection.xml +0 -0
  164. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_files/test_analysis_features.xml +0 -0
  165. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_handlers.py +0 -0
  166. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/test_load.py +0 -0
  167. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/.eslintrc +0 -0
  168. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/analysisSpec.js +0 -0
  169. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/annotationSpec.js +0 -0
  170. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/girderUISpec.js +0 -0
  171. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/huiSpec.js +0 -0
  172. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/huiTest.js +0 -0
  173. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/itemSpec.js +0 -0
  174. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/metadataPanelSpec.js +0 -0
  175. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/metadataPlotSpec.js +0 -0
  176. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/overviewPanelSpec.js +0 -0
  177. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/panelLayoutSpec.js +0 -0
  178. {histomicsui-1.4.7.dev44 → histomicsui-1.4.7.dev49}/tests/web_client_specs/pixelmapCategorySpec.js +0 -0
@@ -84,7 +84,7 @@ jobs:
84
84
  steps:
85
85
  - checkout
86
86
  - tox:
87
- env: flake8,lintclient
87
+ env: lint,lintclient
88
88
  release:
89
89
  docker:
90
90
  - image: girder/tox-and-node
@@ -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.4.0
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.5
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.10.1
70
+ rev: v3.15.0
64
71
  hooks:
65
72
  - id: pyupgrade
66
73
  args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: histomicsui
3
- Version: 1.4.7.dev44
3
+ Version: 1.4.7.dev49
4
4
  Summary: Organize, visualize, and analyze histology images.
5
5
  Home-page: https://github.com/DigitalSlideArchive/histomicsui
6
6
  Author: Kitware, Inc.
@@ -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
- raise ValidationException('The banner color may not be empty', 'value')
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
- raise ValidationException('The banner color must be a hex color triplet', 'value')
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
- raise ValidationException('The brand name may not be empty', 'value')
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
- raise ValidationException('The webroot path may not be empty', 'value')
175
+ msg = 'The webroot path may not be empty'
176
+ raise ValidationException(msg, 'value')
171
177
  if re.match(r'^girder$', doc['value']):
172
- raise ValidationException('The webroot path may not be "girder"', 'value')
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
- raise ValidationException('The alternate webroot path may not contain "girder"', 'value')
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
- 'You must be logged in or have a valid auth token.')
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
- raise Exception('File is larger than will be read into memory.')
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
- raise RestException('The quarantine folder is not configured.')
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
- raise RestException('The quarantine folder does not exist.')
197
+ msg = 'The quarantine folder does not exist.'
198
+ raise RestException(msg)
196
199
  if str(folder['_id']) == str(item['folderId']):
197
- raise RestException('The item is already in the quarantine folder.')
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
- raise RestException('The item has no quarantine record.')
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
- raise RestException('The original folder is not accessible.')
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
- 'The item is not associated with a valid image.'
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
- 'The annotation item must have exactly one file.'
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
- raise ValidationException('Invalid model type')
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
- 'A Case model must be a child of a folder'
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
- 'A Case model must be a child of a cohort'
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
- 'Invalid label in TCGA metadata'
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
- 'Invalid folder document'
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
- 'A Cohort model must be a child of a collection'
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
- 'An image item must be a "large_image"'
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
- 'An image must be a child of a slide'
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
- 'Invalid case name in TCGA metadata'
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
- 'Invalid barcode in TCGA metadata'
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
- 'Invalid uuid in TCGA metadata'
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
- 'Could not generate a large_image item'
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
- 'Could not find a TCGA slide in item'
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
- 'Invalid item document'
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
- 'TCGA collection id not initialized in settings'
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
- raise ValidationException('Invalid name')
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
- 'Invalid document id provided'
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)
@@ -25,4 +25,5 @@ class Pathology(TCGAModel, Item):
25
25
  except ValidationException:
26
26
  pass
27
27
  else:
28
- raise ValidationException('Invalid model type')
28
+ msg = 'Invalid model type'
29
+ raise ValidationException(msg)
@@ -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
- 'A Slide model must be a child of a folder'
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
- 'A Slide model must be a child of a case'
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
- 'Invalid folder document'
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: