Skip to content

Commit

Permalink
Release 0.9.2
Browse files Browse the repository at this point in the history
  • Loading branch information
lucalianas committed Feb 18, 2022
2 parents 63702e1 + de3c9a6 commit fe97206
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 35 deletions.
2 changes: 1 addition & 1 deletion promort/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.9.1
0.9.2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.1.13 on 2022-02-18 14:17

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('predictions_manager', '0002_auto_20210915_1608'),
]

operations = [
migrations.AddField(
model_name='prediction',
name='review_required',
field=models.BooleanField(default=False),
),
]
5 changes: 5 additions & 0 deletions promort/predictions_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ class Prediction(models.Model):
type = models.CharField(max_length=7, choices=PREDICTION_TYPES, blank=False, null=False)
omero_id = models.IntegerField(blank=True, null=True, default=None)
provenance = models.TextField(blank=True, null=True)
review_required = models.BooleanField(blank=False, null=False, default=False)

def require_review(self):
self.review_required = True
self.save()


class TissueFragmentsCollection(models.Model):
Expand Down
8 changes: 5 additions & 3 deletions promort/predictions_manager/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class PredictionSerializer(serializers.ModelSerializer):

class Meta:
model = Prediction
fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance')
fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance',
'review_required')
read_only_fields = ('id', 'creation_date')

def validate_provenance(self, value):
Expand All @@ -48,8 +49,9 @@ class PredictionDetailsSerializer(serializers.ModelSerializer):

class Meta:
model = Prediction
fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance')
read_only_fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance')
fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance', 'review_required')
read_only_fields = ('id', 'label', 'creation_date', 'slide', 'type', 'omero_id', 'provenance',
'review_required')


class TissueFragmentsCollectionSerializer(serializers.ModelSerializer):
Expand Down
16 changes: 16 additions & 0 deletions promort/predictions_manager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ class PredictionDetail(GenericDetailView):
permission_classes = (permissions.IsAuthenticated, )


class PredictionRequireReview(APIView):
permission_classes = (permissions.IsAuthenticated, )

def _find_prediction(self, label):
try:
prediction = Prediction.objects.get(label=label)
return prediction
except Prediction.DoesNotExist:
raise NotFound(f'No prediction review item with label \'{label}\'')

def put(self, request, label, format=None):
prediction = self._find_prediction(label)
prediction.require_review()
return Response(status=status.HTTP_204_NO_CONTENT)


class TissueFragmentsCollectionList(GenericListView):
model = TissueFragmentsCollection
model_serializer = TissueFragmentsCollectionSerializer
Expand Down
67 changes: 37 additions & 30 deletions promort/promort/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@


class NumericString:
regex = '[0-9]+'
regex = r'[0-9]+'

def to_python(self, value):
return value
Expand All @@ -52,11 +52,18 @@ def to_url(self, value):
return value


class SemiSlug:
"""
A slug comprising letters from A to F
"""
regex = r'[A-Fa-f0-9\-.]+'
class RandomCaseLabel:
regex = r'[A-Fa-f0-9]+'

def to_python(self, value):
return value

def to_url(self, value):
return value


class RandomSlideLabel:
regex = r'[A-Fa-f0-9]+\-[A-Za-z0-9]+'

def to_python(self, value):
return value
Expand All @@ -66,7 +73,8 @@ def to_url(self, value):


register_converter(NumericString, 'num')
register_converter(SemiSlug, 'semislug')
register_converter(RandomCaseLabel, 'rclabel')
register_converter(RandomSlideLabel, 'rslabel')

urlpatterns = [
# authentication
Expand Down Expand Up @@ -118,14 +126,13 @@ def to_url(self, value):
qmv.QuestionnairePanelAnswersDetail.as_view()),

# ROIs annotation steps details
path(
'api/rois_annotation_steps/<semislug:label>/clinical_annotation_steps/',
rmv.ClinicalAnnotationStepsList.as_view()),
path('api/rois_annotation_steps/<rslabel:label>/clinical_annotation_steps/',
rmv.ClinicalAnnotationStepsList.as_view()),

# ROIs
path('api/rois_annotation_steps/<semislug:label>/rois_list/',
path('api/rois_annotation_steps/<rslabel:label>/rois_list/',
ROIsTreeList.as_view()),
path('api/rois_annotation_steps/<semislug:label>/slices/',
path('api/rois_annotation_steps/<rslabel:label>/slices/',
SliceList.as_view()),
path('api/slices/<num:pk>/cores/', CoreList.as_view()),
path('api/slices/<num:pk>/', SliceDetail.as_view()),
Expand All @@ -135,38 +142,38 @@ def to_url(self, value):

# clinical annotations data
path(
'api/rois_annotation_steps/<semislug:rois_annotation_step>/rois_list/<semislug:clinical_annotation_step>/',
'api/rois_annotation_steps/<rslabel:rois_annotation_step>/rois_list/<rslabel:clinical_annotation_step>/',
AnnotatedROIsTreeList.as_view()),
path(
'api/clinical_annotation_steps/<semislug:clinical_annotation_step>/annotations_list/',
'api/clinical_annotation_steps/<rslabel:clinical_annotation_step>/annotations_list/',
ClinicalAnnotationStepAnnotationsList.as_view()),
path('api/slices/<num:slice_id>/clinical_annotations/',
SliceAnnotationList.as_view()),
path('api/slices/<num:slice_id>/clinical_annotations/<semislug:label>/',
path('api/slices/<num:slice_id>/clinical_annotations/<rslabel:label>/',
SliceAnnotationDetail.as_view()),
path('api/cores/<num:core_id>/clinical_annotations/',
CoreAnnotationList.as_view()),
path('api/cores/<num:core_id>/clinical_annotations/<semislug:label>/',
path('api/cores/<num:core_id>/clinical_annotations/<rslabel:label>/',
CoreAnnotationDetail.as_view()),
path('api/focus_regions/<num:focus_region_id>/clinical_annotations/',
FocusRegionAnnotationList.as_view()),
path(
'api/focus_regions/<num:focus_region_id>/clinical_annotations/<semislug:label>/',
'api/focus_regions/<num:focus_region_id>/clinical_annotations/<rslabel:label>/',
FocusRegionAnnotationDetail.as_view()),

# ROIs annotations
path('api/rois_annotations/', rmv.ROIsAnnotationsList.as_view()),
path('api/rois_annotations/annotations/<semislug:label>/',
path('api/rois_annotations/annotations/<rclabel:label>/',
rmv.ROIsAnnotationDetail.as_view()),
path('api/rois_annotations/steps/<semislug:label>/reset/',
path('api/rois_annotations/steps/<rslabel:label>/reset/',
rmv.ROIsAnnotationStepReopen.as_view()),
path('api/rois_annotations/steps/<semislug:label>/',
path('api/rois_annotations/steps/<rslabel:label>/',
rmv.ROIsAnnotationStepDetail.as_view()),
path('api/rois_annotations/<slug:case>/',
rmv.ROIsAnnotationsDetail.as_view()),

# quality control
path('api/rois_annotations/steps/<semislug:label>/slide_evaluation/',
path('api/rois_annotations/steps/<rslabel:label>/slide_evaluation/',
SlideEvaluationDetail.as_view()),
path('api/rois_annotations/<slug:case>/<slug:reviewer>/',
rmv.ROIsAnnotationCreation.as_view()),
Expand All @@ -177,9 +184,9 @@ def to_url(self, value):
path('api/clinical_annotations/', rmv.ClinicalAnnotationsList.as_view()),
path('api/clinical_annotations/<slug:case>/',
rmv.ClinicalAnnotationsDetail.as_view()),
path('api/clinical_annotations/annotations/<semislug:label>/',
path('api/clinical_annotations/annotations/<rclabel:label>/',
rmv.ClinicalAnnotationDetail.as_view()),
path('api/clinical_annotations/steps/<semislug:label>/',
path('api/clinical_annotations/steps/<rslabel:label>/',
rmv.ClinicalAnnotationStepDetail.as_view()),
path(
'api/clinical_annotations/<slug:case>/<slug:reviewer>/<num:rois_review>/',
Expand All @@ -191,12 +198,13 @@ def to_url(self, value):
# predictions reviews
path('api/prediction_reviews/', rmv.PredictionReviewsList.as_view()),
path('api/prediction_reviews/<slug:slide>/', rmv.PredictionReviewsDetail.as_view()),
path('api/prediction_review/<semislug:label>/', rmv.PredictionReviewDetail.as_view()),
path('api/prediction_review/<semislug:label>/prediction/', rmv.PredictionByReviewDetail.as_view()),
path('api/prediction_review/<rclabel:label>/', rmv.PredictionReviewDetail.as_view()),
path('api/prediction_review/<rclabel:label>/prediction/', rmv.PredictionByReviewDetail.as_view()),

# predictions
path('api/predictions/', pmv.PredictionList.as_view()),
path('api/predictions/<slug:pk>/', pmv.PredictionDetail.as_view()),
path('api/predictions/<slug:pk>/require_review/', pmv.PredictionRequireReview.as_view()),

# tissue fragments
path('api/tissue_fragments_collections/',
Expand All @@ -206,15 +214,14 @@ def to_url(self, value):
), # GET, DELETE, PUT (se usi GenericDetailView)
path('api/tissue_fragments_collections/<slug:coll_id>/fragments/',
pmv.TissueFragmentList.as_view()), # POST
path(
'api/tissue_fragments_collections/<slug:coll_id>/fragments/<slug:pk>/',
pmv.TissueFragmentsDetail.as_view()), # DELETE
path('api/tissue_fragments_collections/<slug:coll_id>/fragments/<slug:pk>/',
pmv.TissueFragmentsDetail.as_view()), # DELETE

# worklists
path('api/worklist/', UserWorkList.as_view()),
path('api/worklist/rois_annotations/<semislug:label>/',
path('api/worklist/rois_annotations/<rclabel:label>/',
UserWorklistROIsAnnotation.as_view()),
path('api/worklist/clinical_annotations/<semislug:label>/',
path('api/worklist/clinical_annotations/<rclabel:label>/',
UserWorklistClinicalAnnotation.as_view()),
path('api/worklist/admin/<slug:username>/', WorkListAdmin.as_view()),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def _get_prediction_reviews_manager_users(self):
return prev_manager_group.user_set.all()

def _get_predictions_list(self, prediction_type):
return Prediction.objects.filter(type=prediction_type).all()
return Prediction.objects.filter(type=prediction_type, review_required=True).all()

def _check_duplicated(self, prediction, reviewer):
annotation_objs = PredictionReview.objects.filter(prediction=prediction, reviewer=reviewer)
Expand Down

0 comments on commit fe97206

Please sign in to comment.