From cc89a620df23740d9d214f1f5e4784d2eefdf694 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 14:58:28 -0500 Subject: [PATCH 1/7] added ui_mode as an option --- libs/labelbox/src/labelbox/schema/ontology.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 32d5a3884..45f400c24 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -98,7 +98,7 @@ class Classification: removed in a future release. Dropdown will also no longer be able to be created in the Editor on 3/31/2022. - A classfication to be added to a Project's ontology. The + A classification to be added to a Project's ontology. The classification is dependent on the Classification Type. To instantiate, the "class_type" and "name" parameters must @@ -125,8 +125,10 @@ class Classification: instructions: (str) required: (bool) options: (list) + ui_mode: (str) schema_id: (str) feature_schema_id: (str) + scope: (str) """ class Type(Enum): @@ -138,6 +140,10 @@ class Type(Enum): class Scope(Enum): GLOBAL = "global" INDEX = "index" + + class UiMode(Enum): + HOTKEY = "hotkey" + SEARCHABLE = "searchable" _REQUIRES_OPTIONS = {Type.CHECKLIST, Type.RADIO, Type.DROPDOWN} @@ -149,6 +155,7 @@ class Scope(Enum): schema_id: Optional[str] = None feature_schema_id: Optional[str] = None scope: Scope = None + ui_mode: UiMode = None def __post_init__(self): if self.class_type == Classification.Type.DROPDOWN: @@ -180,6 +187,7 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]: instructions=dictionary["instructions"], required=dictionary.get("required", False), options=[Option.from_dict(o) for o in dictionary["options"]], + ui_mode =dictionary.get("uiMode", None), schema_id=dictionary.get("schemaNodeId", None), feature_schema_id=dictionary.get("featureSchemaId", None), scope=cls.Scope(dictionary.get("scope", cls.Scope.GLOBAL))) @@ -195,6 +203,7 @@ def asdict(self, is_subclass: bool = False) -> Dict[str, Any]: "name": self.name, "required": self.required, "options": [o.asdict() for o in self.options], + "uiMode": None if self.class_type == self.Type.TEXT else self.ui_mode.value, # added since this is does nothing for text "schemaNodeId": self.schema_id, "featureSchemaId": self.feature_schema_id } From 522b8f889e7725af75d3588b3f398f5ad6d46dec Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:07:03 -0500 Subject: [PATCH 2/7] changed Ui to UI --- libs/labelbox/src/labelbox/schema/ontology.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 45f400c24..b83b8518a 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -141,7 +141,7 @@ class Scope(Enum): GLOBAL = "global" INDEX = "index" - class UiMode(Enum): + class UIMode(Enum): HOTKEY = "hotkey" SEARCHABLE = "searchable" @@ -155,7 +155,7 @@ class UiMode(Enum): schema_id: Optional[str] = None feature_schema_id: Optional[str] = None scope: Scope = None - ui_mode: UiMode = None + ui_mode: UIMode = None def __post_init__(self): if self.class_type == Classification.Type.DROPDOWN: From 1e36e5c629c1d0546f116b29928261cae54fab8c Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:31:11 -0500 Subject: [PATCH 3/7] added basic unit test --- libs/labelbox/src/labelbox/schema/ontology.py | 8 ++-- .../labelbox/tests/unit/test_unit_ontology.py | 10 ++++ test.py | 46 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 test.py diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index b83b8518a..73a4fd4ba 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -155,7 +155,7 @@ class UIMode(Enum): schema_id: Optional[str] = None feature_schema_id: Optional[str] = None scope: Scope = None - ui_mode: UIMode = None + ui_mode: UIMode = None # How this classification should be answered (e.g. hotkeys / autocomplete, etc) def __post_init__(self): if self.class_type == Classification.Type.DROPDOWN: @@ -187,7 +187,7 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]: instructions=dictionary["instructions"], required=dictionary.get("required", False), options=[Option.from_dict(o) for o in dictionary["options"]], - ui_mode =dictionary.get("uiMode", None), + ui_mode=cls.UIMode(dictionary["uiMode"]) if "uiMode" in dictionary else None, schema_id=dictionary.get("schemaNodeId", None), feature_schema_id=dictionary.get("featureSchemaId", None), scope=cls.Scope(dictionary.get("scope", cls.Scope.GLOBAL))) @@ -203,10 +203,12 @@ def asdict(self, is_subclass: bool = False) -> Dict[str, Any]: "name": self.name, "required": self.required, "options": [o.asdict() for o in self.options], - "uiMode": None if self.class_type == self.Type.TEXT else self.ui_mode.value, # added since this is does nothing for text "schemaNodeId": self.schema_id, "featureSchemaId": self.feature_schema_id } + if (self.class_type == self.Type.RADIO or self.class_type == self.Type.CHECKLIST) and self.ui_mode: + # added because this key does nothing for text so no point of including + classification["uiMode"] = self.ui_mode.value if is_subclass: return classification classification[ diff --git a/libs/labelbox/tests/unit/test_unit_ontology.py b/libs/labelbox/tests/unit/test_unit_ontology.py index 82c709663..ac53827c6 100644 --- a/libs/labelbox/tests/unit/test_unit_ontology.py +++ b/libs/labelbox/tests/unit/test_unit_ontology.py @@ -2,6 +2,7 @@ from labelbox.exceptions import InconsistentOntologyException from labelbox import Tool, Classification, Option, OntologyBuilder +from itertools import product _SAMPLE_ONTOLOGY = { "tools": [{ @@ -46,6 +47,8 @@ "nested classification", "type": "radio", + 'uiMode': + "searchable", "options": [{ "schemaNodeId": None, @@ -120,6 +123,8 @@ "radio", "scope": "global", + 'uiMode': + "searchable", "options": [{ "schemaNodeId": None, "featureSchemaId": None, @@ -148,6 +153,11 @@ def test_create_classification(class_type) -> None: c = Classification(class_type=class_type, name="classification") assert (c.class_type == class_type) +@pytest.mark.parametrize("ui_mode_type, class_type", list(product(list(Classification.UIMode), list(Classification.Type)))) +def test_create_classification_with_ui_mode(ui_mode_type, class_type) -> None: + c = Classification(name="classification", class_type=class_type, ui_mode=ui_mode_type) + assert (c.ui_mode == ui_mode_type) + @pytest.mark.parametrize("value, expected_value, typing", [(3, 3, int), ("string", "string", str)]) diff --git a/test.py b/test.py new file mode 100644 index 000000000..6cea84e93 --- /dev/null +++ b/test.py @@ -0,0 +1,46 @@ +import labelbox as lb +from pprint import pprint +from api_key import API_KEY +client = lb.Client(API_KEY) + +ontology_builder = lb.OntologyBuilder( + classifications=[ + lb.Classification( + class_type=lb.Classification.Type.CHECKLIST, + name="nested_checklist_question", + + options=[ + lb.Option( + "first_checklist_answer", + options=[ + lb.Classification( + class_type=lb.Classification.Type.CHECKLIST, + name="sub_checklist_question", + options=[lb.Option("first_sub_checklist_answer")], + ui_mode=None + ), + + ]) + ], + ui_mode=lb.Classification.UIMode.SEARCHABLE), + ] +) +ontology_builder_2 = lb.OntologyBuilder( + classifications=[ + lb.Classification( + class_type=lb.Classification.Type.TEXT, + name="nested_checklist_question", + ui_mode=lb.Classification.UIMode.SEARCHABLE), + ] +) + +text = lb.Classification( + class_type=lb.Classification.Type.TEXT, + name="nested_checklist_question", + ui_mode=lb.Classification.UIMode.SEARCHABLE) +pprint(ontology_builder.asdict()) + +pprint(ontology_builder_2.asdict()) + +print(text.ui_mode) +# ontology = client.create_ontology(name="test_editor_one_nested", normalized=ontology_builder.asdict(), media_type=lb.MediaType.Image) \ No newline at end of file From f7855e5a75112ad3c3119970c50cddc6bf3ba052 Mon Sep 17 00:00:00 2001 From: Gabe <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:32:13 -0500 Subject: [PATCH 4/7] Delete test.py --- test.py | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 6cea84e93..000000000 --- a/test.py +++ /dev/null @@ -1,46 +0,0 @@ -import labelbox as lb -from pprint import pprint -from api_key import API_KEY -client = lb.Client(API_KEY) - -ontology_builder = lb.OntologyBuilder( - classifications=[ - lb.Classification( - class_type=lb.Classification.Type.CHECKLIST, - name="nested_checklist_question", - - options=[ - lb.Option( - "first_checklist_answer", - options=[ - lb.Classification( - class_type=lb.Classification.Type.CHECKLIST, - name="sub_checklist_question", - options=[lb.Option("first_sub_checklist_answer")], - ui_mode=None - ), - - ]) - ], - ui_mode=lb.Classification.UIMode.SEARCHABLE), - ] -) -ontology_builder_2 = lb.OntologyBuilder( - classifications=[ - lb.Classification( - class_type=lb.Classification.Type.TEXT, - name="nested_checklist_question", - ui_mode=lb.Classification.UIMode.SEARCHABLE), - ] -) - -text = lb.Classification( - class_type=lb.Classification.Type.TEXT, - name="nested_checklist_question", - ui_mode=lb.Classification.UIMode.SEARCHABLE) -pprint(ontology_builder.asdict()) - -pprint(ontology_builder_2.asdict()) - -print(text.ui_mode) -# ontology = client.create_ontology(name="test_editor_one_nested", normalized=ontology_builder.asdict(), media_type=lb.MediaType.Image) \ No newline at end of file From 3b0a94aea9757a167a1b784b435d97b53c7eaa8c Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:44:57 -0500 Subject: [PATCH 5/7] adjusted from_dict to .get to be consistent --- libs/labelbox/src/labelbox/schema/ontology.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 73a4fd4ba..6ac3e7425 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -187,7 +187,7 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]: instructions=dictionary["instructions"], required=dictionary.get("required", False), options=[Option.from_dict(o) for o in dictionary["options"]], - ui_mode=cls.UIMode(dictionary["uiMode"]) if "uiMode" in dictionary else None, + ui_mode=cls.UIMode(dictionary.get("uiMode", None)), schema_id=dictionary.get("schemaNodeId", None), feature_schema_id=dictionary.get("featureSchemaId", None), scope=cls.Scope(dictionary.get("scope", cls.Scope.GLOBAL))) From ca0bacb7b821d500252974a03a2fe5070a9f7363 Mon Sep 17 00:00:00 2001 From: Gabefire <33893811+Gabefire@users.noreply.github.com> Date: Wed, 12 Jun 2024 17:47:27 -0500 Subject: [PATCH 6/7] reverted previous commit --- libs/labelbox/src/labelbox/schema/ontology.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 6ac3e7425..73a4fd4ba 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -187,7 +187,7 @@ def from_dict(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]: instructions=dictionary["instructions"], required=dictionary.get("required", False), options=[Option.from_dict(o) for o in dictionary["options"]], - ui_mode=cls.UIMode(dictionary.get("uiMode", None)), + ui_mode=cls.UIMode(dictionary["uiMode"]) if "uiMode" in dictionary else None, schema_id=dictionary.get("schemaNodeId", None), feature_schema_id=dictionary.get("featureSchemaId", None), scope=cls.Scope(dictionary.get("scope", cls.Scope.GLOBAL))) From 2cab25874513117720334418e9a807598af7e6c5 Mon Sep 17 00:00:00 2001 From: Gabe <33893811+Gabefire@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:51:10 -0500 Subject: [PATCH 7/7] Update libs/labelbox/src/labelbox/schema/ontology.py Co-authored-by: Val Brodsky --- libs/labelbox/src/labelbox/schema/ontology.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/labelbox/src/labelbox/schema/ontology.py b/libs/labelbox/src/labelbox/schema/ontology.py index 73a4fd4ba..f6c758faa 100644 --- a/libs/labelbox/src/labelbox/schema/ontology.py +++ b/libs/labelbox/src/labelbox/schema/ontology.py @@ -155,7 +155,7 @@ class UIMode(Enum): schema_id: Optional[str] = None feature_schema_id: Optional[str] = None scope: Scope = None - ui_mode: UIMode = None # How this classification should be answered (e.g. hotkeys / autocomplete, etc) + ui_mode: Optional[UIMode] = None # How this classification should be answered (e.g. hotkeys / autocomplete, etc) def __post_init__(self): if self.class_type == Classification.Type.DROPDOWN: