Skip to content

Conversation

@lukas-lightly
Copy link
Contributor

What has changed and why?

We want to expose creating and reading annotations collections.

Also added support to annotations_service for setting annotation collection name, e.g. you can have "ground truth" and "prediction" annotation collections.

How has it been tested?

Added tests.

Did you update CHANGELOG.md?

  • Yes
  • Not needed (internal change)

Also added support to annotations_service for setting annotation
collection name, e.g. you can have "ground truth" and "prediction"
annotation collections.
@lukas-lightly
Copy link
Contributor Author

/review

lukas-lightly and others added 2 commits January 21, 2026 11:50
Compared to read_annotations(), read_annotations_by_collection_name()
does not allow filtering by annotation collection ID, as that conflicts
with filtering by collection name.
description="Types of annotation to filter (e.g., 'object_detection')",
)
collection_ids: list[UUID] | None = Field(default=None, description="List of collection UUIDs")
collection_names: list[str] | None = Field(default=None, description="List of collection names")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we should pair annotation collection name with parent collection ID.

I assume that we can have multiple parent collections whose annotations are grouped into "predictions" and "ground truth", so the name won't be unique.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should. Do you want to do this in this PR or a follow-up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should. Do you want to do this in this PR or a follow-up?

I think it makes sense to do this in a followup. We need to drop the uniqueness requirement on annotation collection name first, before it makes sense to include the parent collection ID. Currently the annotation collection name has to be unique, so it's sufficient to identify the collection.

)

@model_validator(mode="after")
def check_collection_identifiers(self) -> AnnotationsFilter: # noqa: N804
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add a test for this, but in the next PR as this one is already too big IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: I would not mind if we leave out the check. All conditions in the filter are combined with and, it is a valid behaviour to return an empty set.

description="Types of annotation to filter (e.g., 'object_detection')",
)
collection_ids: list[UUID] | None = Field(default=None, description="List of collection UUIDs")
collection_names: list[str] | None = Field(default=None, description="List of collection names")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should. Do you want to do this in this PR or a follow-up?

)

@model_validator(mode="after")
def check_collection_identifiers(self) -> AnnotationsFilter: # noqa: N804
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: I would not mind if we leave out the check. All conditions in the filter are combined with and, it is a valid behaviour to return an empty set.

tag_ids: Annotated[list[UUID] | None, Query()] = None,
) -> GetAllAnnotationsResult:
"""Retrieve a list of annotations from the database."""
return annotation_resolver.get_all_by_collection_name(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to remove get_all_by_collection_name resolver function and just use get_all with properly set filter. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done that locally, we can rely on AnnotationsFilter instead.



@annotations_router.get(
"/annotations/collection-name/{annotation_collection_name}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this endpoint fits well with the other endpoints here. Let's discuss in person.



@annotations_router.get(
"/annotations/collection-name/{annotation_collection_name}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a new endpoint? We could use read_annotations and add the annotation_collection_name as an optional parameter, and then as Michal suggested pass it in the filter

Copy link
Contributor Author

@lukas-lightly lukas-lightly Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's jump on a call.

We have two disjoint use cases:

  • querying annotation collection by ID
  • querying annotation collection by name and parent collection ID
    In Rust I could consume an enum (sum type) as an argument, something like:
enum Query {
  ById(UUID),
  ByName(String, UUID)
}

To emulate this in a HTTP API, it's best IMO to have two separate endpoints, but I'm open to suggestions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative would be to remove the collection ID from the arguments and pass the filter directly instead. IMO that would be the cleanest, however it would require changes to the current endpoint calls.

Copy link
Contributor

@michal-lightly michal-lightly Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, there is the parallel "with payload" endpoint, broadening the "impact radius" of changes.

@lukas-lightly
Copy link
Contributor Author

Closing after offline discussion. read_annotations_by_collection_name endpoint won't be needed, as the UI always knows the annotation collection ID.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants