diff --git a/apiv2/db_import/importers/annotation.py b/apiv2/db_import/importers/annotation.py index 187c1c4f5..6502097c0 100644 --- a/apiv2/db_import/importers/annotation.py +++ b/apiv2/db_import/importers/annotation.py @@ -106,7 +106,9 @@ def get_filters(self) -> dict[str, Any]: def get_finder_args(self) -> dict[str, Any]: return { "path": os.path.join(self.tomogram_voxel_spacing.s3_prefix, "Annotations/"), - "file_glob": "*/*.json", + # Use *[0-9].json to match only annotation metadata files (e.g., foo-1.0.json) + # and exclude annotation data files which have a _{shape} suffix (e.g., foo-1.0_globalcaption.json) + "file_glob": "*/*[0-9].json", } diff --git a/apiv2/db_import/tests/conftest.py b/apiv2/db_import/tests/conftest.py index 11b8dfb06..ae4eebec6 100644 --- a/apiv2/db_import/tests/conftest.py +++ b/apiv2/db_import/tests/conftest.py @@ -133,5 +133,5 @@ def expected_dataset(http_prefix: str) -> dict[str, Any]: "key_photo_url": f"{http_prefix}/{DATASET_ID}/KeyPhoto/snapshot.png", "key_photo_thumbnail_url": f"{http_prefix}/{DATASET_ID}/KeyPhoto/thumbnail.png", "deposition_id": 300, - "file_size": 1374849.0, + "file_size": 1375370.0, } diff --git a/apiv2/db_import/tests/test_db_annotation_import.py b/apiv2/db_import/tests/test_db_annotation_import.py index 9d1750c0e..62afeacf6 100644 --- a/apiv2/db_import/tests/test_db_annotation_import.py +++ b/apiv2/db_import/tests/test_db_annotation_import.py @@ -54,6 +54,15 @@ def expected_annotations(http_prefix: str) -> list[dict[str, Any]]: def expected_annotation_files(http_prefix: str) -> list[dict[str, Any]]: path = f"{DATASET_ID}/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/" return [ + { + "tomogram_voxel_spacing_id": TOMOGRAM_VOXEL_ID1, + "s3_path": f"s3://test-public-bucket/{path}100-foo-1.0_globalcaption.json", + "https_path": f"{http_prefix}/{path}100-foo-1.0_globalcaption.json", + "source": "community", + "format": "saber", + "is_visualization_default": False, + "file_size": 0, + }, { "tomogram_voxel_spacing_id": TOMOGRAM_VOXEL_ID1, "s3_path": f"s3://test-public-bucket/{path}100-foo-1.0_instancesegmask.mrc", diff --git a/apiv2/graphql_api/types/annotation_shape.py b/apiv2/graphql_api/types/annotation_shape.py index 326fc065a..4a615fbb0 100644 --- a/apiv2/graphql_api/types/annotation_shape.py +++ b/apiv2/graphql_api/types/annotation_shape.py @@ -197,7 +197,7 @@ class AnnotationShape(EntityInterface): Annotated["AnnotationFileAggregate", strawberry.lazy("graphql_api.types.annotation_file")] ] = load_annotation_file_aggregate_rows # type:ignore shape_type: Optional[annotation_file_shape_type_enum] = strawberry.field( - description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask)", + description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask, GlobalCaption)", default=None, ) id: int = strawberry.field(description="Numeric identifier (May change!)") @@ -312,7 +312,7 @@ class AnnotationShapeCreateInput: description="Metadata about an shapes for an annotation", default=None, ) shape_type: Optional[annotation_file_shape_type_enum] = strawberry.field( - description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask)", + description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask, GlobalCaption)", default=None, ) id: int = strawberry.field(description="Numeric identifier (May change!)") @@ -324,7 +324,7 @@ class AnnotationShapeUpdateInput: description="Metadata about an shapes for an annotation", default=None, ) shape_type: Optional[annotation_file_shape_type_enum] = strawberry.field( - description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask)", + description="The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask, GlobalCaption)", default=None, ) id: Optional[int] = strawberry.field(description="Numeric identifier (May change!)") diff --git a/apiv2/schema/schema.yaml b/apiv2/schema/schema.yaml index 92068187d..2a44f550a 100644 --- a/apiv2/schema/schema.yaml +++ b/apiv2/schema/schema.yaml @@ -285,6 +285,9 @@ enums: Mesh: text: Mesh description: A surface mesh volumes + GlobalCaption: + text: GlobalCaption + description: A text caption for the tomogram annotation_method_link_type_enum: name: annotation_method_link_type_enum description: Describes the type of link associated to the annotation method. @@ -925,11 +928,11 @@ classes: annotations: cascade_delete: true shape_type: - description: The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask) + description: The shape of the annotation (SegmentationMask, OrientedPoint, Point, InstanceSegmentation, Mesh, InstanceSegmentationMask, GlobalCaption) name: shape_type from_schema: cdp-dataset-config range: annotation_file_shape_type_enum - pattern: (^SegmentationMask$)|(^OrientedPoint$)|(^Point$)|(^InstanceSegmentation$)|(^Mesh$)|(^InstanceSegmentationMask$) + pattern: (^SegmentationMask$)|(^OrientedPoint$)|(^Point$)|(^InstanceSegmentation$)|(^Mesh$)|(^InstanceSegmentationMask$)|(^GlobalCaption$) Annotation: name: Annotation annotations: diff --git a/apiv2/support/enums.py b/apiv2/support/enums.py index f281dcaf4..94937ad70 100644 --- a/apiv2/support/enums.py +++ b/apiv2/support/enums.py @@ -40,6 +40,7 @@ class annotation_file_shape_type_enum(enum.StrEnum): InstanceSegmentation = "InstanceSegmentation" InstanceSegmentationMask = "InstanceSegmentationMask" Mesh = "Mesh" + GlobalCaption = "GlobalCaption" @strawberry.enum diff --git a/apiv2/test_infra/factories/annotation_shape.py b/apiv2/test_infra/factories/annotation_shape.py index 6de536ad4..0209fedb0 100644 --- a/apiv2/test_infra/factories/annotation_shape.py +++ b/apiv2/test_infra/factories/annotation_shape.py @@ -33,7 +33,15 @@ class Meta: AnnotationFactory, ) shape_type = fuzzy.FuzzyChoice( - ["SegmentationMask", "OrientedPoint", "Point", "InstanceSegmentation", "InstanceSegmentationMask", "Mesh"], + [ + "SegmentationMask", + "OrientedPoint", + "Point", + "InstanceSegmentation", + "InstanceSegmentationMask", + "Mesh", + "GlobalCaption", + ], ) # Auto increment integer identifiers starting with 1 diff --git a/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/100-foo-1.0_globalcaption.json b/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/100-foo-1.0_globalcaption.json new file mode 100644 index 000000000..711f79416 --- /dev/null +++ b/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/100-foo-1.0_globalcaption.json @@ -0,0 +1,16 @@ +{ + "captions": [ + { + "id": 0, + "text": "A caption for tomogram X." + }, + { + "id": 1, + "text": "A 2nd caption for tomogram X." + }, + { + "id": 2, + "text": "A 3rd caption for tomogram X." + } + ] +} diff --git a/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/foo-1.0.json b/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/foo-1.0.json index 46ea06db4..013f3358a 100644 --- a/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/foo-1.0.json +++ b/test_infra/test_files/30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100/foo-1.0.json @@ -66,6 +66,12 @@ "path": "30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100-foo-1.0_instancesegmask.zarr", "shape": "InstanceSegmentationMask", "is_visualization_default": false + }, + { + "format": "saber", + "path": "30001/RUN1/Reconstructions/VoxelSpacing12.300/Annotations/100-foo-1.0_globalcaption.json", + "shape": "GlobalCaption", + "is_visualization_default": false } ], "method_links": [