From 206046e664666da63fd87caf923d3598a3590771 Mon Sep 17 00:00:00 2001 From: nupursharma-labellerr Date: Tue, 2 Dec 2025 12:55:11 +0530 Subject: [PATCH 1/5] [LABIMP-8415] Added text based project support : --- labellerr/core/projects/__init__.py | 2 ++ labellerr/core/projects/text_project.py | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 labellerr/core/projects/text_project.py diff --git a/labellerr/core/projects/__init__.py b/labellerr/core/projects/__init__.py index 2c737be..89ba938 100644 --- a/labellerr/core/projects/__init__.py +++ b/labellerr/core/projects/__init__.py @@ -10,6 +10,7 @@ from .document_project import DocucmentProject as LabellerrDocumentProject from .image_project import ImageProject as LabellerrImageProject from .video_project import VideoProject as LabellerrVideoProject +from .text_project import TextProject as LabellerrTextProject from .base import LabellerrProject from ..annotation_templates import LabellerrAnnotationTemplate from typing import List @@ -20,6 +21,7 @@ "LabellerrDocumentProject", "LabellerrImageProject", "LabellerrVideoProject", + "LabellerrTextProject", ] diff --git a/labellerr/core/projects/text_project.py b/labellerr/core/projects/text_project.py new file mode 100644 index 0000000..904f136 --- /dev/null +++ b/labellerr/core/projects/text_project.py @@ -0,0 +1,9 @@ +from .base import LabellerrProject, LabellerrProjectMeta + + +class TextProject(LabellerrProject): + + pass + + +LabellerrProjectMeta._register("text", TextProject) From 01adf9a794652acb28dc1e322742c58d169cfc1d Mon Sep 17 00:00:00 2001 From: nupursharma-labellerr Date: Tue, 9 Dec 2025 11:36:35 +0530 Subject: [PATCH 2/5] [LABIMP-8422] List templates API integration --- .../core/annotation_templates/__init__.py | 31 ++++++++++++++++++- labellerr/core/annotation_templates/base.py | 28 +++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/labellerr/core/annotation_templates/__init__.py b/labellerr/core/annotation_templates/__init__.py index f89441b..f807b2c 100644 --- a/labellerr/core/annotation_templates/__init__.py +++ b/labellerr/core/annotation_templates/__init__.py @@ -1,8 +1,15 @@ from .base import LabellerrAnnotationTemplate -from ..schemas.annotation_templates import CreateTemplateParams, QuestionType, Option +from ..schemas.annotation_templates import ( + CreateTemplateParams, + QuestionType, + Option, + DatasetDataType, +) from .. import constants from ..client import LabellerrClient import uuid +from typing import List + __all__ = [ "LabellerrAnnotationTemplate", @@ -62,3 +69,25 @@ def create_template( client=client, annotation_template_id=response.get("response", None).get("template_id"), ) + + +def list_templates( + client: LabellerrClient, data_type: DatasetDataType +) -> List[LabellerrAnnotationTemplate]: + """ """ + unique_id = str(uuid.uuid4()) + url = ( + f"{constants.BASE_URL}/annotations/list_questions_templates?client_id={client.client_id}&data_type={data_type}" + f"&uuid={unique_id}" + ) + + response = client.make_request( + "GET", + url, + extra_headers={"content-type": "application/json"}, + request_id=unique_id, + ) + return [ + LabellerrAnnotationTemplate(client, item.get("template_id")) + for item in response.get("response", []) + ] diff --git a/labellerr/core/annotation_templates/base.py b/labellerr/core/annotation_templates/base.py index 21a24af..8622197 100644 --- a/labellerr/core/annotation_templates/base.py +++ b/labellerr/core/annotation_templates/base.py @@ -45,6 +45,28 @@ def __new__(cls, client: "LabellerrClient", annotation_template_id: str): def __init__(self, client: "LabellerrClient", annotation_template_id: str): self.client = client - self.annotation_template_id = annotation_template_id - # Use the data already fetched in __new__ - self.annotation_template_data = self.__annotation_template_data + self.__annotation_template_id = annotation_template_id + + @property + def template_name(self): + return self.__annotation_template_data.get("template_name") + + @property + def data_type(self): + return self.__annotation_template_data.get("data_type") + + @property + def template_id(self): + return self.__annotation_template_id + + @property + def created_at(self): + return self.__annotation_template_data.get("created_at") + + @property + def created_by(self): + return self.__annotation_template_data.get("created_by") + + @property + def questions(self): + return self.__annotation_template_data.get("questions") From 844171b39d19688cd664d3be383921bd5cb417e3 Mon Sep 17 00:00:00 2001 From: Ximi Hoque Date: Tue, 9 Dec 2025 16:59:06 +0530 Subject: [PATCH 3/5] Fixed claude comments --- .../core/annotation_templates/__init__.py | 12 +++-- labellerr/core/annotation_templates/base.py | 51 +++++++++++++++++-- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/labellerr/core/annotation_templates/__init__.py b/labellerr/core/annotation_templates/__init__.py index f807b2c..82a607a 100644 --- a/labellerr/core/annotation_templates/__init__.py +++ b/labellerr/core/annotation_templates/__init__.py @@ -74,10 +74,16 @@ def create_template( def list_templates( client: LabellerrClient, data_type: DatasetDataType ) -> List[LabellerrAnnotationTemplate]: - """ """ + """ + List all annotation templates for a given data type + + :param client: The client to use for the request. + :param data_type: The data type to list templates for. + :return: A list of LabellerrAnnotationTemplate instances. + """ unique_id = str(uuid.uuid4()) url = ( - f"{constants.BASE_URL}/annotations/list_questions_templates?client_id={client.client_id}&data_type={data_type}" + f"{constants.BASE_URL}/annotations/list_questions_templates?client_id={client.client_id}&data_type={data_type.value}" f"&uuid={unique_id}" ) @@ -88,6 +94,6 @@ def list_templates( request_id=unique_id, ) return [ - LabellerrAnnotationTemplate(client, item.get("template_id")) + LabellerrAnnotationTemplate.from_annotation_template_data(client, **item) for item in response.get("response", []) ] diff --git a/labellerr/core/annotation_templates/base.py b/labellerr/core/annotation_templates/base.py index 8622197..d40c17b 100644 --- a/labellerr/core/annotation_templates/base.py +++ b/labellerr/core/annotation_templates/base.py @@ -24,8 +24,14 @@ def get_annotation_template(client: "LabellerrClient", annotation_template_id: s """Base class for all Labellerr projects with factory behavior""" - def __new__(cls, client: "LabellerrClient", annotation_template_id: str): - # Validate that the annotation template exists before creating the instance + def __new__(cls, client: "LabellerrClient", annotation_template_id: str, **kwargs): + # If annotation_template_data is provided in kwargs, use it directly + if "annotation_template_data" in kwargs: + instance = super().__new__(cls) + instance.__annotation_template_data = kwargs["annotation_template_data"] + return instance + + # Otherwise, fetch from API annotation_template_data = cls.get_annotation_template( client, annotation_template_id ) @@ -43,9 +49,46 @@ def __new__(cls, client: "LabellerrClient", annotation_template_id: str): instance.__annotation_template_data = annotation_template_data return instance - def __init__(self, client: "LabellerrClient", annotation_template_id: str): + def __init__( + self, client: "LabellerrClient", annotation_template_id: str, **kwargs + ): self.client = client - self.__annotation_template_id = annotation_template_id + if "annotation_template_data" in kwargs: + self.__annotation_template_id = kwargs["annotation_template_data"].get( + "template_id" + ) + else: + self.__annotation_template_id = annotation_template_id + + @classmethod + def from_annotation_template_data(cls, client: "LabellerrClient", **kwargs): + """ + Create a LabellerrAnnotationTemplate instance from annotation template data. + + :param client: LabellerrClient instance + :param kwargs: Annotation template fields (template_id, template_name, questions, etc.) + :return: Instance of LabellerrAnnotationTemplate + """ + # Validate required fields + required_fields = { + "template_id", + "template_name", + "questions", + "created_at", + "created_by", + } + missing_fields = required_fields - set(kwargs.keys()) + if missing_fields: + raise ValueError( + f"Missing required fields in annotation_template_data: {missing_fields}" + ) + + # Create instance without calling API - pass annotation_template_data to skip API call + return cls( + client, + annotation_template_id=kwargs.get("template_id"), + annotation_template_data=kwargs, + ) @property def template_name(self): From fbb739623a8299b9b54be6be15a70244de5cecc9 Mon Sep 17 00:00:00 2001 From: Ximi Hoque Date: Tue, 9 Dec 2025 17:35:31 +0530 Subject: [PATCH 4/5] Fixed claude comments --- labellerr/core/annotation_templates/base.py | 45 +++++++++++---------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/labellerr/core/annotation_templates/base.py b/labellerr/core/annotation_templates/base.py index d40c17b..14619a8 100644 --- a/labellerr/core/annotation_templates/base.py +++ b/labellerr/core/annotation_templates/base.py @@ -24,14 +24,12 @@ def get_annotation_template(client: "LabellerrClient", annotation_template_id: s """Base class for all Labellerr projects with factory behavior""" - def __new__(cls, client: "LabellerrClient", annotation_template_id: str, **kwargs): - # If annotation_template_data is provided in kwargs, use it directly - if "annotation_template_data" in kwargs: - instance = super().__new__(cls) - instance.__annotation_template_data = kwargs["annotation_template_data"] - return instance - - # Otherwise, fetch from API + def __new__(cls, client: "LabellerrClient", annotation_template_id: str, _skip_api_fetch: bool = False, **kwargs): + # If skip flag is set, create instance without API call + if _skip_api_fetch: + return super().__new__(cls) + + # Otherwise, fetch from API and validate annotation_template_data = cls.get_annotation_template( client, annotation_template_id ) @@ -43,22 +41,26 @@ def __new__(cls, client: "LabellerrClient", annotation_template_id: str, **kwarg f"Annotation template with ID '{annotation_template_id}' does not exist or could not be retrieved." ) - # Create the instance only if validation passes - instance = super().__new__(cls) - # Store the data on the instance to avoid calling API again in __init__ - instance.__annotation_template_data = annotation_template_data - return instance + # Pass fetched data to __init__ via kwargs + kwargs["_fetched_data"] = annotation_template_data + return super().__new__(cls) def __init__( - self, client: "LabellerrClient", annotation_template_id: str, **kwargs + self, client: "LabellerrClient", annotation_template_id: str, _skip_api_fetch: bool = False, **kwargs ): self.client = client - if "annotation_template_data" in kwargs: - self.__annotation_template_id = kwargs["annotation_template_data"].get( - "template_id" - ) + self.__annotation_template_id = annotation_template_id + + # Set __annotation_template_data from either source + if "_cached_data" in kwargs: + # Data provided directly (from factory method) + self.__annotation_template_data = kwargs["_cached_data"] + elif "_fetched_data" in kwargs: + # Data fetched in __new__ + self.__annotation_template_data = kwargs["_fetched_data"] else: - self.__annotation_template_id = annotation_template_id + # Fallback - shouldn't happen in normal usage + self.__annotation_template_data = {} @classmethod def from_annotation_template_data(cls, client: "LabellerrClient", **kwargs): @@ -83,11 +85,12 @@ def from_annotation_template_data(cls, client: "LabellerrClient", **kwargs): f"Missing required fields in annotation_template_data: {missing_fields}" ) - # Create instance without calling API - pass annotation_template_data to skip API call + # Create instance without API call - explicit flag makes intent clear return cls( client, annotation_template_id=kwargs.get("template_id"), - annotation_template_data=kwargs, + _skip_api_fetch=True, + _cached_data=kwargs, ) @property From aa274a8166f96d40a933504124ac22fdbffb35f2 Mon Sep 17 00:00:00 2001 From: Ximi Hoque Date: Tue, 9 Dec 2025 17:39:59 +0530 Subject: [PATCH 5/5] linter fixes --- labellerr/core/annotation_templates/base.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/labellerr/core/annotation_templates/base.py b/labellerr/core/annotation_templates/base.py index 14619a8..2a13909 100644 --- a/labellerr/core/annotation_templates/base.py +++ b/labellerr/core/annotation_templates/base.py @@ -24,7 +24,13 @@ def get_annotation_template(client: "LabellerrClient", annotation_template_id: s """Base class for all Labellerr projects with factory behavior""" - def __new__(cls, client: "LabellerrClient", annotation_template_id: str, _skip_api_fetch: bool = False, **kwargs): + def __new__( + cls, + client: "LabellerrClient", + annotation_template_id: str, + _skip_api_fetch: bool = False, + **kwargs, + ): # If skip flag is set, create instance without API call if _skip_api_fetch: return super().__new__(cls) @@ -46,11 +52,15 @@ def __new__(cls, client: "LabellerrClient", annotation_template_id: str, _skip_a return super().__new__(cls) def __init__( - self, client: "LabellerrClient", annotation_template_id: str, _skip_api_fetch: bool = False, **kwargs + self, + client: "LabellerrClient", + annotation_template_id: str, + _skip_api_fetch: bool = False, + **kwargs, ): self.client = client self.__annotation_template_id = annotation_template_id - + # Set __annotation_template_data from either source if "_cached_data" in kwargs: # Data provided directly (from factory method)