diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b489c37..53dc80d2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # Changelog +# Version 3.61.0 (2024-01-22) +# Added +* `ModelSlice.get_data_row_identifiers` + * Fetches all data row ids and global keys for the model slice + * NOTE Foundry model slices are note supported yet +## Updated +* Updated exports v1 deprecation date to April 30th, 2024 +* Remove `streamable` param from export_v2 methods + # Version 3.60.0 (2024-01-17) ## Added * Get resource tags from a project diff --git a/docs/source/conf.py b/docs/source/conf.py index 6d24efa07..e23163c91 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,7 +21,7 @@ copyright = '2021, Labelbox' author = 'Labelbox' -release = '3.60.0' +release = '3.61.0' # -- General configuration --------------------------------------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 769d7b1fe..1fb52553c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -203,19 +203,11 @@ ResourceTag :members: :show-inheritance: -Slice ------------------------------------------ - -.. automodule:: labelbox.schema.slice - :members: Slice - :exclude-members: CatalogSlice - :show-inheritance: -CatalogSlice ------------------------------------------ -.. automodule:: labelbox.schema.slice - :members: CatalogSlice - :exclude-members: Slice +Slice +--------------------------- +.. automodule:: labelbox.schema.slices + :members: :show-inheritance: QualityMode diff --git a/examples/basics/Export_V1_to_V2_migration_support.ipynb b/examples/basics/Export_V1_to_V2_migration_support.ipynb index 2b5250154..70e9a7051 100644 --- a/examples/basics/Export_V1_to_V2_migration_support.ipynb +++ b/examples/basics/Export_V1_to_V2_migration_support.ipynb @@ -40,7 +40,7 @@ { "metadata": {}, "source": [ - "**Export V1 will no longer be available in any version of the SDK starting on April 20, 2024**. We recommend users to plan accordingly. \n", + "**Export V1 will no longer be available in any version of the SDK starting on April 2024**. We recommend users to plan accordingly. \n", "\n", "This notebook is designed to help users identify alternative V2 export methods that can serve as replacements for V1 methods." ], @@ -51,9 +51,9 @@ "source": [ "### Key changes included in export V2 methods (``export_v2()`` and ``export()``):\n", "1. Added flexibility to only export the data that is needed. The new methods include parameters and filters to give you more granular control over your exports.\n", - "2. Added functionality to stream your data export. \n", + "2. Added functionality to stream your data export using ``export()`` (available on SDK >=3.56)\n", "\n", - "For complete details on how to use exports V2 please see the [Export overview](https://docs.labelbox.com/reference/label-export#optional-parameters-and-filters) documentation." + "For complete details on how to use export V2 methods please see the [Export V2 methods](https://docs.labelbox.com/reference/label-export#export-v2-methods) documentation." ], "cell_type": "markdown" }, @@ -198,7 +198,7 @@ " name='bounding_box',\n", " feature_schema_id='clrf5ck4a0b9b071paa9ncu15',\n", " extra={\n", - " 'instanceURI': 'https://api.labelbox.com/masks/feature/clrf5csvi6ofm07lsf9pygwvi?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJjbGh0OHNocXUweW53MDc0aWRuZDUyemd1Iiwib3JnYW5pemF0aW9uSWQiOiJjbDVibjhxdnExYXY5MDd4dGIzYnA4cTYwIiwiaWF0IjoxNzA1NDMxOTE3LCJleHAiOjE3MDgwMjM5MTd9.BSKLVSbKTNmp9tcYt-PncIBeZ2Hrw4kCOz3qyxvAoOY',\n", + " 'instanceURI': 'https://api.labelbox.com/masks/feature/clrf5csvi6ofm07lsf9pygwvi?token='\n", " 'color': '#ff0000',\n", " 'feature_id': 'clrf5csvi6ofm07lsf9pygwvi',\n", " 'value': 'bounding_box',\n", diff --git a/labelbox/__init__.py b/labelbox/__init__.py index 4a09efcdd..8a20ec508 100644 --- a/labelbox/__init__.py +++ b/labelbox/__init__.py @@ -1,6 +1,6 @@ name = "labelbox" -__version__ = "3.60.0" +__version__ = "3.61.0" from labelbox.client import Client from labelbox.schema.project import Project diff --git a/labelbox/client.py b/labelbox/client.py index 4470190f9..c00a64c79 100644 --- a/labelbox/client.py +++ b/labelbox/client.py @@ -1696,6 +1696,10 @@ def get_model_slice(self, slice_id) -> ModelSlice: } """ res = self.execute(query_str, {"id": slice_id}) + if res is None or res["getSavedQuery"] is None: + raise labelbox.exceptions.ResourceNotFoundError( + ModelSlice, slice_id) + return Entity.ModelSlice(self, res["getSavedQuery"]) def delete_feature_schema_from_ontology( diff --git a/labelbox/schema/batch.py b/labelbox/schema/batch.py index 19f1b72ff..313d02c16 100644 --- a/labelbox/schema/batch.py +++ b/labelbox/schema/batch.py @@ -105,7 +105,7 @@ def export_data_rows(self, LabelboxError: if the export fails or is unable to download within the specified time. """ warnings.warn( - "You are currently utilizing exports v1 for this action, which will be deprecated after December 31st, 2023. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", + "You are currently utilizing exports v1 for this action, which will be deprecated after April 30th, 2024. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", DeprecationWarning) id_param = "batchId" diff --git a/labelbox/schema/data_row.py b/labelbox/schema/data_row.py index 9b0667d5f..ebe279d52 100644 --- a/labelbox/schema/data_row.py +++ b/labelbox/schema/data_row.py @@ -188,12 +188,12 @@ def export( >>> task.wait_till_done() >>> task.result """ - task = DataRow.export_v2(client, - data_rows, - global_keys, - task_name, - params, - streamable=True) + task = DataRow._export(client, + data_rows, + global_keys, + task_name, + params, + streamable=True) return ExportTask(task) @staticmethod @@ -203,7 +203,6 @@ def export_v2( global_keys: Optional[List[str]] = None, task_name: Optional[str] = None, params: Optional[CatalogExportParams] = None, - streamable: bool = False, ) -> Task: """ Creates a data rows export task with the given list, params and returns the task. @@ -228,7 +227,18 @@ def export_v2( >>> task.wait_till_done() >>> task.result """ + return DataRow._export(client, data_rows, global_keys, task_name, + params) + @staticmethod + def _export( + client: "Client", + data_rows: Optional[List[Union[str, "DataRow"]]] = None, + global_keys: Optional[List[str]] = None, + task_name: Optional[str] = None, + params: Optional[CatalogExportParams] = None, + streamable: bool = False, + ) -> Task: _params = params or CatalogExportParams({ "attachments": False, "metadata_fields": False, diff --git a/labelbox/schema/dataset.py b/labelbox/schema/dataset.py index 9aa1ea5c5..8ef194c78 100644 --- a/labelbox/schema/dataset.py +++ b/labelbox/schema/dataset.py @@ -561,7 +561,7 @@ def export_data_rows(self, LabelboxError: if the export fails or is unable to download within the specified time. """ warnings.warn( - "You are currently utilizing exports v1 for this action, which will be deprecated after December 31st, 2023. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", + "You are currently utilizing exports v1 for this action, which will be deprecated after April 30th, 2024. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", DeprecationWarning) id_param = "datasetId" metadata_param = "includeMetadataInput" @@ -619,7 +619,7 @@ def export( >>> task.wait_till_done() >>> task.result """ - task = self.export_v2(task_name, filters, params, streamable=True) + task = self._export(task_name, filters, params, streamable=True) return ExportTask(task) def export_v2( @@ -627,7 +627,6 @@ def export_v2( task_name: Optional[str] = None, filters: Optional[DatasetExportFilters] = None, params: Optional[CatalogExportParams] = None, - streamable: bool = False, ) -> Task: """ Creates a dataset export task with the given params and returns the task. @@ -646,7 +645,15 @@ def export_v2( >>> task.wait_till_done() >>> task.result """ + return self._export(task_name, filters, params) + def _export( + self, + task_name: Optional[str] = None, + filters: Optional[DatasetExportFilters] = None, + params: Optional[CatalogExportParams] = None, + streamable: bool = False, + ) -> Task: _params = params or CatalogExportParams({ "attachments": False, "metadata_fields": False, diff --git a/labelbox/schema/model_run.py b/labelbox/schema/model_run.py index 564df9694..ba56f2640 100644 --- a/labelbox/schema/model_run.py +++ b/labelbox/schema/model_run.py @@ -477,7 +477,7 @@ def export_labels( None is returned. """ warnings.warn( - "You are currently utilizing exports v1 for this action, which will be deprecated after December 31st, 2023. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", + "You are currently utilizing exports v1 for this action, which will be deprecated after April 30th, 2024. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", DeprecationWarning) sleep_time = 2 query_str = """mutation exportModelRunAnnotationsPyApi($modelRunId: ID!) { @@ -518,14 +518,13 @@ def export(self, >>> export_task = export("my_export_task", params={"media_attributes": True}) """ - task = self.export_v2(task_name, params, streamable=True) + task = self._export(task_name, params, streamable=True) return ExportTask(task) def export_v2( self, task_name: Optional[str] = None, params: Optional[ModelRunExportParams] = None, - streamable: bool = False, ) -> Task: """ Creates a model run export task with the given params and returns the task. @@ -533,6 +532,14 @@ def export_v2( >>> export_task = export_v2("my_export_task", params={"media_attributes": True}) """ + return self._export(task_name, params) + + def _export( + self, + task_name: Optional[str] = None, + params: Optional[ModelRunExportParams] = None, + streamable: bool = False, + ) -> Task: mutation_name = "exportDataRowsInModelRun" create_task_query_str = ( f"mutation {mutation_name}PyApi" @@ -541,7 +548,7 @@ def export_v2( _params = params or ModelRunExportParams() - queryParams = { + query_params = { "input": { "taskName": task_name, "filters": { @@ -563,7 +570,7 @@ def export_v2( } } res = self.client.execute(create_task_query_str, - queryParams, + query_params, error_log_key="errors") res = res[mutation_name] task_id = res["taskId"] diff --git a/labelbox/schema/project.py b/labelbox/schema/project.py index 2ca085c20..9fe774d6c 100644 --- a/labelbox/schema/project.py +++ b/labelbox/schema/project.py @@ -271,7 +271,7 @@ def export_queued_data_rows( LabelboxError: if the export fails or is unable to download within the specified time. """ warnings.warn( - "You are currently utilizing exports v1 for this action, which will be deprecated after December 31st, 2023. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", + "You are currently utilizing exports v1 for this action, which will be deprecated after April 30th, 2024. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", DeprecationWarning) id_param = "projectId" metadata_param = "includeMetadataInput" @@ -377,7 +377,7 @@ def export_labels(self, generate during the `timeout_seconds` period, None is returned. """ warnings.warn( - "You are currently utilizing exports v1 for this action, which will be deprecated after December 31st, 2023. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", + "You are currently utilizing exports v1 for this action, which will be deprecated after April 30th, 2024. We recommend transitioning to exports v2. To view export v2 details, visit our docs: https://docs.labelbox.com/reference/label-export", DeprecationWarning) def _string_from_dict(dictionary: dict, value_with_quotes=False) -> str: @@ -477,7 +477,7 @@ def export( >>> task.wait_till_done() >>> task.result """ - task = self.export_v2(task_name, filters, params, streamable=True) + task = self._export(task_name, filters, params, streamable=True) return ExportTask(task) def export_v2( @@ -485,7 +485,6 @@ def export_v2( task_name: Optional[str] = None, filters: Optional[ProjectExportFilters] = None, params: Optional[ProjectExportParams] = None, - streamable: bool = False, ) -> Task: """ Creates a project export task with the given params and returns the task. @@ -506,7 +505,15 @@ def export_v2( >>> task.wait_till_done() >>> task.result """ + return self._export(task_name, filters, params) + def _export( + self, + task_name: Optional[str] = None, + filters: Optional[ProjectExportFilters] = None, + params: Optional[ProjectExportParams] = None, + streamable: bool = False, + ) -> Task: _params = params or ProjectExportParams({ "attachments": False, "metadata_fields": False, diff --git a/labelbox/schema/slice.py b/labelbox/schema/slice.py index 15fff2277..e7a538da7 100644 --- a/labelbox/schema/slice.py +++ b/labelbox/schema/slice.py @@ -29,12 +29,6 @@ class Slice(DbObject): updated_at = Field.DateTime("updated_at") filter = Field.Json("filter") - -class CatalogSlice(Slice): - """ - Represents a Slice used for filtering data rows in Catalog. - """ - @dataclass class DataRowIdAndGlobalKey: id: UniqueId @@ -44,6 +38,18 @@ def __init__(self, id: str, global_key: Optional[str]): self.id = UniqueId(id) self.global_key = GlobalKey(global_key) if global_key else None + def to_hash(self): + return { + "id": self.id.key, + "global_key": self.global_key.key if self.global_key else None + } + + +class CatalogSlice(Slice): + """ + Represents a Slice used for filtering data rows in Catalog. + """ + def get_data_row_ids(self) -> PaginatedCollection: """ Fetches all data row ids that match this Slice @@ -75,7 +81,7 @@ def get_data_row_ids(self) -> PaginatedCollection: return PaginatedCollection( client=self.client, query=query_str, - params={'id': self.uid}, + params={'id': str(self.uid)}, dereferencing=['getDataRowIdsBySavedQuery', 'nodes'], obj_class=lambda _, data_row_id: data_row_id, cursor_path=['getDataRowIdsBySavedQuery', 'pageInfo', 'endCursor']) @@ -85,7 +91,7 @@ def get_data_row_identifiers(self) -> PaginatedCollection: Fetches all data row ids and global keys (where defined) that match this Slice Returns: - A PaginatedCollection of data row ids + A PaginatedCollection of Slice.DataRowIdAndGlobalKey """ query_str = """ query getDataRowIdenfifiersBySavedQueryPyApi($id: ID!, $from: String, $first: Int!) { @@ -112,9 +118,9 @@ def get_data_row_identifiers(self) -> PaginatedCollection: query=query_str, params={'id': str(self.uid)}, dereferencing=['getDataRowIdentifiersBySavedQuery', 'nodes'], - obj_class=lambda _, data_row_id_and_gk: CatalogSlice. - DataRowIdAndGlobalKey(data_row_id_and_gk.get('id'), - data_row_id_and_gk.get('globalKey', None)), + obj_class=lambda _, data_row_id_and_gk: Slice.DataRowIdAndGlobalKey( + data_row_id_and_gk.get('id'), + data_row_id_and_gk.get('globalKey', None)), cursor_path=[ 'getDataRowIdentifiersBySavedQuery', 'pageInfo', 'endCursor' ]) @@ -132,14 +138,13 @@ def export(self, >>> task.wait_till_done() >>> task.result """ - task = self.export_v2(task_name, params, streamable=True) + task = self._export(task_name, params, streamable=True) return ExportTask(task) def export_v2( self, task_name: Optional[str] = None, params: Optional[CatalogExportParams] = None, - streamable: bool = False, ) -> Task: """ Creates a slice export task with the given params and returns the task. @@ -150,7 +155,14 @@ def export_v2( >>> task.wait_till_done() >>> task.result """ + return self._export(task_name, params) + def _export( + self, + task_name: Optional[str] = None, + params: Optional[CatalogExportParams] = None, + streamable: bool = False, + ) -> Task: _params = params or CatalogExportParams({ "attachments": False, "metadata_fields": False, @@ -224,6 +236,33 @@ class ModelSlice(Slice): Represents a Slice used for filtering data rows in Model. """ + @classmethod + def query_str(cls): + query_str = """ + query getDataRowIdenfifiersBySavedModelQueryPyApi($id: ID!, $from: DataRowIdentifierCursorInput, $first: Int!) { + getDataRowIdentifiersBySavedModelQuery(input: { + savedQueryId: $id, + after: $from + first: $first + }) { + totalCount + nodes + { + id + globalKey + } + pageInfo { + endCursor { + dataRowId + globalKey + } + hasNextPage + } + } + } + """ + return query_str + def get_data_row_ids(self) -> PaginatedCollection: """ Fetches all data row ids that match this Slice @@ -231,26 +270,34 @@ def get_data_row_ids(self) -> PaginatedCollection: Returns: A PaginatedCollection of data row ids """ - query_str = """ - query getDataRowIdsBySavedQueryPyApi($id: ID!, $from: String, $first: Int!) { - getDataRowIdsBySavedQuery(input: { - savedQueryId: $id, - after: $from - first: $first - }) { - totalCount - nodes - pageInfo { - endCursor - hasNextPage - } - } - } + return PaginatedCollection( + client=self.client, + query=ModelSlice.query_str(), + params={'id': str(self.uid)}, + dereferencing=['getDataRowIdentifiersBySavedModelQuery', 'nodes'], + obj_class=lambda _, data_row_id_and_gk: data_row_id_and_gk.get('id' + ), + cursor_path=[ + 'getDataRowIdentifiersBySavedModelQuery', 'pageInfo', + 'endCursor' + ]) + + def get_data_row_identifiers(self) -> PaginatedCollection: + """ + Fetches all data row ids and global keys (where defined) that match this Slice + + Returns: + A PaginatedCollection of Slice.DataRowIdAndGlobalKey """ return PaginatedCollection( client=self.client, - query=query_str, - params={'id': self.uid}, - dereferencing=['getDataRowIdsBySavedQuery', 'nodes'], - obj_class=lambda _, data_row_id: data_row_id, - cursor_path=['getDataRowIdsBySavedQuery', 'pageInfo', 'endCursor']) + query=ModelSlice.query_str(), + params={'id': str(self.uid)}, + dereferencing=['getDataRowIdentifiersBySavedModelQuery', 'nodes'], + obj_class=lambda _, data_row_id_and_gk: Slice.DataRowIdAndGlobalKey( + data_row_id_and_gk.get('id'), + data_row_id_and_gk.get('globalKey', None)), + cursor_path=[ + 'getDataRowIdentifiersBySavedModelQuery', 'pageInfo', + 'endCursor' + ]) diff --git a/tests/integration/annotation_import/fixtures/export_v2.py b/tests/integration/annotation_import/fixtures/export_v2.py index 869999a5c..616351c5c 100644 --- a/tests/integration/annotation_import/fixtures/export_v2.py +++ b/tests/integration/annotation_import/fixtures/export_v2.py @@ -7,6 +7,8 @@ def expected_export_v2_image(): 'objects': [{ 'name': 'polygon', + 'value': + 'polygon', 'annotation_kind': 'ImagePolygon', 'classifications': [], @@ -28,11 +30,14 @@ def expected_export_v2_image(): }] }, { 'name': 'bbox', + 'value': 'bbox', 'annotation_kind': 'ImageBoundingBox', 'classifications': [{ 'name': 'nested', + 'value': 'nested', 'radio_answer': { 'name': 'radio_option_1', + 'value': 'radio_value_1', 'classifications': [] } }], @@ -44,6 +49,7 @@ def expected_export_v2_image(): } }, { 'name': 'polyline', + 'value': 'polyline', 'annotation_kind': 'ImagePolyline', 'classifications': [], 'line': [{ @@ -55,13 +61,18 @@ def expected_export_v2_image(): }] }], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -77,13 +88,18 @@ def expected_export_v2_audio(): expected_annotations = { 'objects': [], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -99,13 +115,18 @@ def expected_export_v2_html(): 'objects': [], 'classifications': [{ 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } }, { - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }], @@ -119,6 +140,7 @@ def expected_export_v2_text(): expected_annotations = { 'objects': [{ 'name': 'named-entity', + 'value': 'named_entity', 'annotation_kind': 'TextEntity', 'classifications': [], 'location': { @@ -127,13 +149,18 @@ def expected_export_v2_text(): } }], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -152,9 +179,13 @@ def expected_export_v2_video(): }, 'key_frame_feature_map': {}, 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }] @@ -167,6 +198,7 @@ def expected_export_v2_conversation(): expected_annotations = { 'objects': [{ 'name': 'named-entity', + 'value': 'named_entity', 'annotation_kind': 'ConversationalTextEntity', 'classifications': [], 'conversational_location': { @@ -180,14 +212,18 @@ def expected_export_v2_conversation(): 'classifications': [{ 'name': 'checklist_index', + 'value': + 'checklist_index', 'message_id': '0', 'conversational_checklist_answers': [{ 'name': 'option1_index', + 'value': 'option1_index', 'classifications': [] }] }, { 'name': 'text_index', + 'value': 'text_index', 'message_id': '0', 'conversational_text_answer': { 'content': 'free form text...' @@ -211,6 +247,8 @@ def expected_export_v2_dicom(): '': { 'name': 'polyline', + 'value': + 'polyline', 'annotation_kind': 'DICOMPolyline', 'classifications': [], @@ -264,6 +302,7 @@ def expected_export_v2_document(): expected_annotations = { 'objects': [{ 'name': 'named-entity', + 'value': 'named_entity', 'annotation_kind': 'DocumentEntityToken', 'classifications': [], 'location': { @@ -288,11 +327,14 @@ def expected_export_v2_document(): } }, { 'name': 'bbox', + 'value': 'bbox', 'annotation_kind': 'DocumentBoundingBox', 'classifications': [{ 'name': 'nested', + 'value': 'nested', 'radio_answer': { 'name': 'radio_option_1', + 'value': 'radio_value_1', 'classifications': [] } }], @@ -305,13 +347,18 @@ def expected_export_v2_document(): } }], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -326,13 +373,18 @@ def expected_export_v2_llm_prompt_creation(): expected_annotations = { 'objects': [], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -347,13 +399,18 @@ def expected_export_v2_llm_prompt_response_creation(): expected_annotations = { 'objects': [], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } @@ -368,13 +425,18 @@ def expected_export_v2_llm_response_creation(): expected_annotations = { 'objects': [], 'classifications': [{ - 'name': 'checklist', + 'name': + 'checklist', + 'value': + 'checklist', 'checklist_answers': [{ 'name': 'option1', + 'value': 'option1', 'classifications': [] }] }, { 'name': 'text', + 'value': 'text', 'text_answer': { 'content': 'free form text...' } diff --git a/tests/integration/test_global_keys.py b/tests/integration/test_global_keys.py index 25ca7ba33..9349b85d4 100644 --- a/tests/integration/test_global_keys.py +++ b/tests/integration/test_global_keys.py @@ -79,15 +79,6 @@ def test_assign_same_global_keys_to_data_rows(client, dataset, image_url): 'error'] == "Invalid assignment. Either DataRow does not exist, or globalKey is invalid" -def test_global_key_sanitization(dataset, image_url): - uuid_str = str(uuid.uuid4()) - unsanitized_global_key = "\"<>\\{\\}\\|" + uuid_str - sanitized_global_key = "_________" + uuid_str - dr = dataset.create_data_row(row_data=image_url, - global_key=unsanitized_global_key) - assert dr.global_key == sanitized_global_key - - def test_long_global_key_validation(client, dataset, image_url): long_global_key = 'x' * 201 dr_1 = dataset.create_data_row(row_data=image_url)