def test_multiple_polygonsets_for_one_grader_distinct(self): grader = UserFactory() grader.groups.add( Group.objects.get(name=settings.RETINA_GRADERS_GROUP_NAME) ) polygon_sets = [ self.annotation_set.polygonset1, PolygonAnnotationSetFactory( grader=grader, image=self.annotation_set.polygonset1.image ), PolygonAnnotationSetFactory( grader=grader, image=self.annotation_set.polygonset1.image ), ] force_authenticate(self.request, user=self.retina_admin) response = self.view(self.request, **self.kwargs) graders = ( get_user_model() .objects.filter( polygonannotationset__in=polygon_sets, groups__name=settings.RETINA_GRADERS_GROUP_NAME, ) .distinct() ) expected_response = UserSerializer(graders, many=True).data expected_response.sort(key=lambda k: k["id"]) assert response.status_code == status.HTTP_200_OK response.data.sort(key=lambda k: k["id"]) assert response.data == expected_response
def test_testsetretinapathologies_old(self): PolygonAnnotationSetFactory(name="No match") PolygonAnnotationSetFactory(name="retina::too_small") result = set_retina_pathologies(PolygonAnnotationSet.objects.all()) assert result["pathology_set"] == 0 assert result["old_annotation"] == 2 assert len(result["non_matching_pathology"]) == 0
def generate_two_polygon_annotation_sets(retina_grader=False): graders = (UserFactory(), UserFactory()) if retina_grader: add_to_graders_group(graders) polygonsets = ( PolygonAnnotationSetFactory(grader=graders[0]), PolygonAnnotationSetFactory(grader=graders[1]), ) # Create child models for polygon annotation set singlepolygonbatches = ( SinglePolygonAnnotationFactory.create_batch( 10, annotation_set=polygonsets[0] ), SinglePolygonAnnotationFactory.create_batch( 10, annotation_set=polygonsets[1] ), ) return TwoPolygonAnnotationSets( grader1=graders[0], grader2=graders[1], polygonset1=polygonsets[0], polygonset2=polygonsets[1], )
def test_testmigratelesionnames_already_migrated(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) PolygonAnnotationSetFactory(name="retina::oct::macular::Drusen", image=image) PolygonAnnotationSetFactory( name="retina::enface::rf_present::Hard drusen") result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 0 assert result["already_translated"] == 2
def test_testmigratelesionnames_correctly_migrated_case_insensitive(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) annotation_oct = PolygonAnnotationSetFactory( name="amd_present::DrUsEn AnD DrUsEn lIkE sTruCtUrEs::HARD dRuSeN", image=image, ) annotation_enface = PolygonAnnotationSetFactory( name="DrUsEn AnD DrUsEn lIkE sTruCtUrEs::HARD dRuSeN") result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 2 annotation_enface.refresh_from_db() assert (annotation_enface.name == "retina::enface::rf_present::Hard drusen") annotation_oct.refresh_from_db() assert annotation_oct.name == "retina::oct::macular::Drusen"
def test_testmigratelesionnames_correctly_migrated(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) annotation_oct = PolygonAnnotationSetFactory( name="amd_present::Drusen and drusen like structures::Hard Drusen", image=image, ) annotation_enface = PolygonAnnotationSetFactory( name="drusen and drusen like structures::hard drusen") result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 2 annotation_enface.refresh_from_db() assert (annotation_enface.name == "retina::enface::rf_present::Hard drusen") annotation_oct.refresh_from_db() assert annotation_oct.name == "retina::oct::macular::Drusen"
def test_testmigratelesionnames_no_match_enface(self): annotation = PolygonAnnotationSetFactory( name= "amd_present::Drusen and drusen like structures::Conical drusen") result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 0 assert result["enface_no_match"] == [annotation.id]
def generate_annotation_set(retina_grader=False): grader = UserFactory() if retina_grader: add_to_graders_group([grader]) measurement = MeasurementAnnotationFactory(grader=grader) boolean = BooleanClassificationAnnotationFactory(grader=grader) integer = IntegerClassificationAnnotationFactory(grader=grader) polygon = PolygonAnnotationSetFactory(grader=grader) coordinatelist = CoordinateListAnnotationFactory(grader=grader) landmark = LandmarkAnnotationSetFactory(grader=grader) etdrs = ETDRSGridAnnotationFactory(grader=grader) # Create child models for polygon annotation set SinglePolygonAnnotationFactory.create_batch(10, annotation_set=polygon) # Create child models for landmark annotation set (3 per image) for i in range(5): image = ImageFactory() SingleLandmarkAnnotationFactory(annotation_set=landmark, image=image) return AnnotationSet( grader=grader, measurement=measurement, boolean=boolean, polygon=polygon, coordinatelist=coordinatelist, landmark=landmark, etdrs=etdrs, integer=integer, )
def test_multiple_graders_some_retina_grader(self): graders = ( UserFactory(), UserFactory(), UserFactory(), UserFactory(), UserFactory(), ) polygon_sets = [self.annotation_set.polygonset1] for index, grader in enumerate(graders): if index % 2 == 0: grader.groups.add( Group.objects.get(name=settings.RETINA_GRADERS_GROUP_NAME) ) polygon_sets.append( PolygonAnnotationSetFactory( grader=grader, image=self.annotation_set.polygonset1.image ) ) force_authenticate(self.request, user=self.retina_admin) response = self.view(self.request, **self.kwargs) graders = get_user_model().objects.filter( polygonannotationset__in=polygon_sets, groups__name=settings.RETINA_GRADERS_GROUP_NAME, ) expected_response = UserSerializer(graders, many=True).data expected_response.sort(key=lambda k: k["id"]) assert response.status_code == status.HTTP_200_OK response.data.sort(key=lambda k: k["id"]) assert response.data == expected_response
def test_update_view(self, TwoRetinaPolygonAnnotationSets, rf, user_type): model_serialized = SinglePolygonAnnotationSerializer( TwoRetinaPolygonAnnotationSets.polygonset1.singlepolygonannotation_set.first() ).data annotation_set = PolygonAnnotationSetFactory( grader=TwoRetinaPolygonAnnotationSets.grader1 ) model_serialized["annotation_set"] = str(annotation_set.id) model_json = json.dumps(model_serialized) response = view_test( "update", user_type, self.namespace, self.basename, TwoRetinaPolygonAnnotationSets.grader1, TwoRetinaPolygonAnnotationSets.polygonset1.singlepolygonannotation_set.first(), rf, SinglePolygonViewSet, model_json, ) if user_type in ("retina_grader", "retina_admin"): response.data["annotation_set"] = str( response.data["annotation_set"] ) assert response.data == model_serialized
def test_create_view(self, TwoRetinaPolygonAnnotationSets, rf, user_type): model_build = SinglePolygonAnnotationFactory.build() model_serialized = SinglePolygonAnnotationSerializer(model_build).data annotation_set = PolygonAnnotationSetFactory( grader=TwoRetinaPolygonAnnotationSets.grader1 ) model_serialized["annotation_set"] = str(annotation_set.id) model_json = json.dumps(model_serialized) response = view_test( "create", user_type, self.namespace, self.basename, TwoRetinaPolygonAnnotationSets.grader1, None, rf, SinglePolygonViewSet, model_json, ) if user_type in ("retina_grader", "retina_admin"): model_serialized["id"] = response.data["id"] response.data["annotation_set"] = str( response.data["annotation_set"] ) assert response.data == model_serialized
def test_testmigratelesionnames_no_match_oct_boolean(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) annotation = PolygonAnnotationSetFactory( name="other_present::Vascular::Branch retinal artery occlusion", image=image, ) result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 0 assert result["boolean_oct_no_match"] == [annotation.id]
def create_load_data(data_type, ds, grader): if data_type == "Registration": model = LandmarkAnnotationSetFactory(grader=grader) SingleLandmarkAnnotationFactory( annotation_set=model, image=ds["image_cf"] ), if ds["archive"].name == "Australia": # Australia does not allow obs images so create a new cf image for Australia test img = ImageFactory(study=ds["study"]) SingleLandmarkAnnotationFactory(annotation_set=model, image=img) else: SingleLandmarkAnnotationFactory( annotation_set=model, image=ds["image_obs"] ), elif data_type == "ETDRS": model = ETDRSGridAnnotationFactory(grader=grader, image=ds["image_cf"]) elif data_type == "GA" or data_type == "kappa": model_macualar = PolygonAnnotationSetFactory( grader=grader, image=ds["image_cf"], name="macular" ) SinglePolygonAnnotationFactory(annotation_set=model_macualar) SinglePolygonAnnotationFactory(annotation_set=model_macualar) SinglePolygonAnnotationFactory(annotation_set=model_macualar) model_peripapillary = PolygonAnnotationSetFactory( grader=grader, image=ds["image_cf"], name="peripapillary" ) SinglePolygonAnnotationFactory(annotation_set=model_peripapillary) SinglePolygonAnnotationFactory(annotation_set=model_peripapillary) SinglePolygonAnnotationFactory(annotation_set=model_peripapillary) model = [model_macualar, model_peripapillary] elif data_type == "Measure": model = [ MeasurementAnnotationFactory(grader=grader, image=ds["image_cf"]), MeasurementAnnotationFactory(grader=grader, image=ds["image_cf"]), MeasurementAnnotationFactory(grader=grader, image=ds["image_cf"]), ] elif data_type == "Fovea": model = BooleanClassificationAnnotationFactory( grader=grader, image=ds["image_cf"], name="fovea_affected" ) return model
def test_testmigratelesionnames_no_match_oct(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) annotation = PolygonAnnotationSetFactory( name= "amd_present::Pigment changes & RPE degeneration::Increased pigmentation", image=image, ) result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 0 assert result["oct_no_match"] == [annotation.id]
def test_testmigratelesionnames_unique_violation_appends(self): annotation = PolygonAnnotationSetFactory( name="drusen and drusen like structures::hard drusen") SinglePolygonAnnotationFactory(annotation_set=annotation), SinglePolygonAnnotationFactory(annotation_set=annotation), annotation_dup = PolygonAnnotationSetFactory( name="retina::enface::rf_present::Hard drusen", grader=annotation.grader, image=annotation.image, created=annotation.created, ) SinglePolygonAnnotationFactory(annotation_set=annotation_dup), SinglePolygonAnnotationFactory(annotation_set=annotation_dup), assert annotation_dup.singlepolygonannotation_set.count() == 2 result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 1 assert result["already_translated"] == 1 assert PolygonAnnotationSet.objects.count() == 1 annotation_dup.refresh_from_db() assert annotation_dup.singlepolygonannotation_set.count() == 4
def test_testsetretinapathologies_no_match(self): annotation = PolygonAnnotationSetFactory( name="retina::enface::non_matching_pathology::bla") result = set_retina_pathologies(PolygonAnnotationSet.objects.all()) assert result["pathology_set"] == 0 assert result["old_annotation"] == 0 assert len(result["non_matching_pathology"]) == 1 assert result["non_matching_pathology"] == [{ "id": annotation.id, "name": annotation.name }]
def test_testmigratelesionnames_combined(self): image = ImageFactory(modality=ImagingModalityFactory(modality="OCT")) annotation_oct = PolygonAnnotationSetFactory( name="amd_present::Drusen and drusen like structures::Hard Drusen", image=image, ) annotation_enface = PolygonAnnotationSetFactory( name="drusen and drusen like structures::hard drusen") PolygonAnnotationSetFactory(name="retina::oct::macular::Drusen", image=image) PolygonAnnotationSetFactory( name="retina::enface::rf_present::Hard drusen") PolygonAnnotationSetFactory( name="other_present::Vascular::Branch retinal artery occlusion", ) annotation_oct_no_match_boolean = PolygonAnnotationSetFactory( name="other_present::Vascular::Branch retinal artery occlusion", image=image, ) annotation_oct_no_match = PolygonAnnotationSetFactory( name= "amd_present::Pigment changes & RPE degeneration::Increased pigmentation", image=image, ) annotation_enface_no_match = PolygonAnnotationSetFactory( name= "amd_present::Drusen and drusen like structures::Conical drusen") annotation_no_match = PolygonAnnotationSetFactory(name="No match") assert BooleanClassificationAnnotation.objects.count() == 0 result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 3 assert BooleanClassificationAnnotation.objects.count() == 1 assert result["already_translated"] == 2 assert result["boolean_oct_no_match"] == [ annotation_oct_no_match_boolean.id ] assert result["oct_no_match"] == [annotation_oct_no_match.id] assert result["enface_no_match"] == [annotation_enface_no_match.id] assert result["no_match"] == [annotation_no_match.id] annotation_enface.refresh_from_db() assert (annotation_enface.name == "retina::enface::rf_present::Hard drusen") annotation_oct.refresh_from_db() assert annotation_oct.name == "retina::oct::macular::Drusen"
def generate_annotation_set(retina_grader=False, image=False): grader = UserFactory() if retina_grader: add_to_graders_group([grader]) create_options = {"grader": grader} if image: create_options_with_image = {"image": image, **create_options} else: create_options_with_image = create_options measurement = MeasurementAnnotationFactory(**create_options_with_image) boolean = BooleanClassificationAnnotationFactory( **create_options_with_image ) integer = IntegerClassificationAnnotationFactory( **create_options_with_image ) polygon = PolygonAnnotationSetFactory(**create_options_with_image) coordinatelist = CoordinateListAnnotationFactory( **create_options_with_image ) etdrs = ETDRSGridAnnotationFactory(**create_options_with_image) landmark = LandmarkAnnotationSetFactory(**create_options) # Create child models for polygon annotation set SinglePolygonAnnotationFactory.create_batch(10, annotation_set=polygon) # Create child models for landmark annotation set (3 per image) single_landmarks = [] for i in range(5): if i > 0 or not image: image = ImageFactory() single_landmarks.append( SingleLandmarkAnnotationFactory( annotation_set=landmark, image=image ) ) return AnnotationSet( grader=grader, measurement=measurement, boolean=boolean, polygon=polygon, coordinatelist=coordinatelist, landmark=landmark, singlelandmarks=single_landmarks, etdrs=etdrs, integer=integer, )
def test_testsetretinapathologies_created(self): annotation = PolygonAnnotationSetFactory( name=f"retina::enface::{pathology_options_enface[0]}::bla") assert RetinaImagePathologyAnnotation.objects.all().count() == 0 result = set_retina_pathologies(PolygonAnnotationSet.objects.all()) assert result["pathology_set"] == 1 assert result["old_annotation"] == 0 assert len(result["non_matching_pathology"]) == 0 assert RetinaImagePathologyAnnotation.objects.all().count() == 1 pathology_annotation = RetinaImagePathologyAnnotation.objects.first() assert pathology_annotation.image == annotation.image assert pathology_annotation.grader == annotation.grader for v in pathology_options_enface: assert getattr(pathology_annotation, v) == (v == pathology_options_enface[0])
def test_testmigratelesionnames_correctly_migrated_boolean(self): annotation_enface = PolygonAnnotationSetFactory( name="other_present::Vascular::Branch retinal artery occlusion") assert BooleanClassificationAnnotation.objects.count() == 0 result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 1 assert PolygonAnnotationSet.objects.count() == 0 assert BooleanClassificationAnnotation.objects.count() == 1 annotation = BooleanClassificationAnnotation.objects.first() assert (annotation.name == "retina::enface::Branch retinal artery occlusion") assert annotation.value assert annotation.grader == annotation_enface.grader assert annotation.image == annotation_enface.image assert annotation.created == annotation_enface.created
def test_testsetretinapathologies_oct(self): annotation = PolygonAnnotationSetFactory( name=f"retina::oct::{pathology_options_oct[0]}::bla") assert OctRetinaImagePathologyAnnotation.objects.all().count() == 0 result = set_retina_pathologies(PolygonAnnotationSet.objects.all()) assert result["pathology_set"] == 1 assert result["old_annotation"] == 0 assert len(result["non_matching_pathology"]) == 0 assert RetinaImagePathologyAnnotation.objects.all().count() == 0 assert OctRetinaImagePathologyAnnotation.objects.all().count() == 1 oct_pathology_annotation = ( OctRetinaImagePathologyAnnotation.objects.first()) assert oct_pathology_annotation.image == annotation.image assert oct_pathology_annotation.grader == annotation.grader assert (getattr(oct_pathology_annotation, pathology_options_oct[0]) is True)
def test_testsetretinapathologies_updated(self): annotation = PolygonAnnotationSetFactory( name=f"retina::enface::{pathology_options_enface[0]}::bla") pathology_annotation = RetinaImagePathologyAnnotationFactory( **{ "image": annotation.image, "grader": annotation.grader, pathology_options_enface[0]: False, }) assert RetinaImagePathologyAnnotation.objects.all().count() == 1 result = set_retina_pathologies(PolygonAnnotationSet.objects.all()) assert result["pathology_set"] == 1 assert result["old_annotation"] == 0 assert len(result["non_matching_pathology"]) == 0 assert RetinaImagePathologyAnnotation.objects.all().count() == 1 pathology_annotation.refresh_from_db() assert pathology_annotation.image == annotation.image assert pathology_annotation.grader == annotation.grader assert (getattr(pathology_annotation, pathology_options_enface[0]) is True)
def test_update_view_wrong_user_id( self, TwoRetinaPolygonAnnotationSets, rf, user_type ): model_serialized = SinglePolygonAnnotationSerializer( TwoRetinaPolygonAnnotationSets.polygonset1.singlepolygonannotation_set.first() ).data annotation_set = PolygonAnnotationSetFactory() model_serialized["annotation_set"] = str(annotation_set.id) model_json = json.dumps(model_serialized) response = view_test( "update", user_type, self.namespace, self.basename, TwoRetinaPolygonAnnotationSets.grader1, TwoRetinaPolygonAnnotationSets.polygonset1.singlepolygonannotation_set.first(), rf, SinglePolygonViewSet, model_json, check_response_status_code=False, ) if user_type == "retina_admin": model_serialized["id"] = response.data["id"] response.data["annotation_set"] = str( response.data["annotation_set"] ) assert response.data == model_serialized elif user_type == "retina_grader": assert response.status_code == status.HTTP_400_BAD_REQUEST assert ( str(response.data["non_field_errors"][0]) == "User is not allowed to create annotation for other grader" ) else: assert response.status_code == status.HTTP_403_FORBIDDEN
def test_testmigratelesionnames_no_match(self): annotation = PolygonAnnotationSetFactory(name="No match") result = migrate_annotations(PolygonAnnotationSet.objects.all()) assert result["translated"] == 0 assert result["no_match"] == [annotation.id]