diff --git a/pyproject.toml b/pyproject.toml index c31051120..1dab59b37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath" -version = "2.6.12" +version = "2.6.13" description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools." readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/src/uipath/platform/documents/_documents_service.py b/src/uipath/platform/documents/_documents_service.py index 2bf09673a..66a8bd09d 100644 --- a/src/uipath/platform/documents/_documents_service.py +++ b/src/uipath/platform/documents/_documents_service.py @@ -1316,13 +1316,13 @@ def _start_classification_validation( project_id: str, project_type: ProjectType, tag: Optional[str], - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, classification_results: List[ClassificationResult], + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> str: if project_type == ProjectType.PRETRAINED: url = Endpoint( @@ -1357,13 +1357,13 @@ async def _start_classification_validation_async( project_id: str, project_type: ProjectType, tag: Optional[str], - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, classification_results: List[ClassificationResult], + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> str: if project_type == ProjectType.PRETRAINED: url = Endpoint( @@ -1402,11 +1402,11 @@ def _start_extraction_validation( tag: Optional[str], document_type_id: str, action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, + action_priority: Optional[ActionPriority], + action_catalog: Optional[str], + action_folder: Optional[str], + storage_bucket_name: Optional[str], + storage_bucket_directory_path: Optional[str], extraction_response: ExtractionResponse, ) -> StartOperationResponse: if project_type == ProjectType.PRETRAINED: @@ -1450,11 +1450,11 @@ async def _start_extraction_validation_async( tag: Optional[str], document_type_id: str, action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, + action_priority: Optional[ActionPriority], + action_catalog: Optional[str], + action_folder: Optional[str], + storage_bucket_name: Optional[str], + storage_bucket_directory_path: Optional[str], extraction_response: ExtractionResponse, ) -> StartOperationResponse: if project_type == ProjectType.PRETRAINED: @@ -1496,24 +1496,24 @@ async def _start_extraction_validation_async( @traced(name="documents_start_ixp_extraction_validation", run_type="uipath") def start_ixp_extraction_validation( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, extraction_response: ExtractionResponseIXP, + action_title: str, + action_catalog: Optional[str] = None, + action_priority: Optional[ActionPriority] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> StartOperationResponse: """Start an IXP extraction validation action without waiting for results (non-blocking). Args: - action_title (str): The title of the validation action. - action_priority (ActionPriority): The priority of the validation action. - action_catalog (str): The catalog of the validation action. - action_folder (str): The folder of the validation action. - storage_bucket_name (str): The name of the storage bucket where validation data will be stored. - storage_bucket_directory_path (str): The directory path within the storage bucket. extraction_response (ExtractionResponseIXP): The extraction response from the IXP extraction process. + action_title (str): The title of the validation action. + action_catalog (str, optional): The catalog of the validation action. + action_priority (ActionPriority, optional): The priority of the validation action. + action_folder (str, optional): The folder of the validation action. + storage_bucket_name (str, optional): The name of the storage bucket where validation data will be stored. + storage_bucket_directory_path (str, optional): The directory path within the storage bucket. Returns: StartOperationResponse: Contains the operation_id, document_id, project_id, and tag. @@ -1552,13 +1552,13 @@ def start_ixp_extraction_validation( ) async def start_ixp_extraction_validation_async( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, extraction_response: ExtractionResponseIXP, + action_title: str, + action_catalog: Optional[str] = None, + action_priority: Optional[ActionPriority] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> StartOperationResponse: """Asynchronous version of the [`start_ixp_extraction_validation`][uipath.platform.documents._documents_service.DocumentsService.start_ixp_extraction_validation] method.""" return await self._start_extraction_validation_async( @@ -1899,24 +1899,24 @@ async def result_getter_async() -> Tuple[Any, Optional[Any], Optional[Any]]: @traced(name="documents_create_validate_classification_action", run_type="uipath") def create_validate_classification_action( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, classification_results: List[ClassificationResult], + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> ValidateClassificationAction: """Create a validate classification action for a document based on the classification results. More details about validation actions can be found in the [official documentation](https://docs.uipath.com/ixp/automation-cloud/latest/user-guide/validating-classifications). Args: - action_title (str): Title of the action. - action_priority (ActionPriority): Priority of the action. - action_catalog (str): Catalog of the action. - action_folder (str): Folder of the action. - storage_bucket_name (str): Name of the storage bucket. - storage_bucket_directory_path (str): Directory path in the storage bucket. classification_results (List[ClassificationResult]): The classification results to be validated, typically obtained from the [`classify`][uipath.platform.documents._documents_service.DocumentsService.classify] method. + action_title (str): Title of the action. + action_priority (ActionPriority, optional): Priority of the action. + action_catalog (str, optional): Catalog of the action. + action_folder (str, optional): Folder of the action. + storage_bucket_name (str, optional): Name of the storage bucket. + storage_bucket_directory_path (str, optional): Directory path in the storage bucket. Returns: ValidateClassificationAction: The created validate classification action. @@ -1960,13 +1960,13 @@ def create_validate_classification_action( @traced(name="documents_create_validate_classification_action", run_type="uipath") async def create_validate_classification_action_async( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, classification_results: List[ClassificationResult], + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> ValidateClassificationAction: """Asynchronous version of the [`create_validation_action`][uipath.platform.documents._documents_service.DocumentsService.create_validate_classification_action] method.""" if not classification_results: @@ -1995,24 +1995,24 @@ async def create_validate_classification_action_async( @traced(name="documents_create_validate_extraction_action", run_type="uipath") def create_validate_extraction_action( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, extraction_response: ExtractionResponse, + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> ValidateExtractionAction: """Create a validate extraction action for a document based on the extraction response. More details about validation actions can be found in the [official documentation](https://docs.uipath.com/ixp/automation-cloud/latest/user-guide/validating-extractions). Args: - action_title (str): Title of the action. - action_priority (ActionPriority): Priority of the action. - action_catalog (str): Catalog of the action. - action_folder (str): Folder of the action. - storage_bucket_name (str): Name of the storage bucket. - storage_bucket_directory_path (str): Directory path in the storage bucket. extraction_response (ExtractionResponse): The extraction result to be validated, typically obtained from the [`extract`][uipath.platform.documents._documents_service.DocumentsService.extract] method. + action_title (str): Title of the action. + action_priority (ActionPriority, optional): Priority of the action. + action_catalog (str, optional): Catalog of the action. + action_folder (str, optional): Folder of the action. + storage_bucket_name (str, optional): Name of the storage bucket. + storage_bucket_directory_path (str, optional): Directory path in the storage bucket. Returns: ValidateClassificationAction: The created validation action. @@ -2055,13 +2055,13 @@ def create_validate_extraction_action( @traced(name="documents_create_validate_extraction_action_async", run_type="uipath") async def create_validate_extraction_action_async( self, - action_title: str, - action_priority: ActionPriority, - action_catalog: str, - action_folder: str, - storage_bucket_name: str, - storage_bucket_directory_path: str, extraction_response: ExtractionResponse, + action_title: str, + action_priority: Optional[ActionPriority] = None, + action_catalog: Optional[str] = None, + action_folder: Optional[str] = None, + storage_bucket_name: Optional[str] = None, + storage_bucket_directory_path: Optional[str] = None, ) -> ValidateExtractionAction: """Asynchronous version of the [`create_validation_action`][uipath.platform.documents._documents_service.DocumentsService.create_validate_extraction_action] method.""" operation_id = ( diff --git a/tests/sdk/services/test_documents_service.py b/tests/sdk/services/test_documents_service.py index 3b9b7c29e..7f033b221 100644 --- a/tests/sdk/services/test_documents_service.py +++ b/tests/sdk/services/test_documents_service.py @@ -1349,6 +1349,78 @@ async def test_create_validate_classification_action_with_empty_classification_r classification_results=[], ) + @pytest.mark.parametrize("mode", ["sync", "async"]) + @pytest.mark.asyncio + async def test_create_validate_classification_action_with_optional_params_omitted( + self, + httpx_mock: HTTPXMock, + service: DocumentsService, + base_url: str, + org: str, + tenant: str, + classification_response: dict, # type: ignore + create_validation_action_response: dict, # type: ignore + mode: str, + ): + # ARRANGE + project_id = str(UUID(int=0)) + operation_id = str(uuid4()) + tag = None + action_title = "TestAction" + + classification_result = classification_response["classificationResults"][0] + classification_result["ProjectId"] = project_id + classification_result["ProjectType"] = ProjectType.PRETRAINED.value + classification_result["Tag"] = tag + classification_result = ClassificationResult.model_validate( + classification_result + ) + + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/du_/api/framework/projects/{project_id}/classifiers/ml-classification/validation/start?api-version=1.1", + status_code=200, + match_headers={"X-UiPath-Internal-ConsumptionSourceType": "CodedAgents"}, + match_json={ + "actionTitle": action_title, + "actionPriority": None, + "actionCatalog": None, + "actionFolder": None, + "storageBucketName": None, + "storageBucketDirectoryPath": None, + "classificationResults": [ + classification_result.model_dump(), + ], + "documentId": classification_result.document_id, + }, + json={"operationId": operation_id}, + ) + + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/du_/api/framework/projects/{project_id}/classifiers/ml-classification/validation/result/{operation_id}?api-version=1.1", + status_code=200, + match_headers={"X-UiPath-Internal-ConsumptionSourceType": "CodedAgents"}, + json={"status": "Succeeded", "result": create_validation_action_response}, + ) + + # ACT + if mode == "async": + response = await service.create_validate_classification_action_async( + classification_results=[classification_result], + action_title=action_title, + ) + else: + response = service.create_validate_classification_action( + classification_results=[classification_result], + action_title=action_title, + ) + + # ASSERT + create_validation_action_response["projectId"] = project_id + create_validation_action_response["projectType"] = ProjectType.PRETRAINED.value + create_validation_action_response["tag"] = tag + create_validation_action_response["operationId"] = operation_id + assert response.model_dump() == create_validation_action_response + @pytest.mark.parametrize("mode", ["sync", "async"]) @pytest.mark.asyncio async def test_create_validate_extraction_action_pretrained( @@ -1546,6 +1618,84 @@ async def test_create_validate_extraction_action_ixp( create_validation_action_response["dataProjection"] = None assert response.model_dump() == create_validation_action_response + @pytest.mark.parametrize("mode", ["sync", "async"]) + @pytest.mark.asyncio + async def test_create_validate_extraction_action_with_optional_params_omitted( + self, + httpx_mock: HTTPXMock, + service: DocumentsService, + base_url: str, + org: str, + tenant: str, + modern_extraction_response: dict, # type: ignore + create_validation_action_response: dict, # type: ignore + mode: str, + ): + # ARRANGE + project_id = str(UUID(int=0)) + operation_id = str(uuid4()) + document_type_id = str(UUID(int=0)) + tag = None + action_title = "TestAction" + + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/du_/api/framework/projects/{project_id}/extractors/{document_type_id}/validation/start?api-version=1.1", + status_code=200, + match_headers={"X-UiPath-Internal-ConsumptionSourceType": "CodedAgents"}, + match_json={ + "extractionResult": modern_extraction_response["extractionResult"], + "documentId": modern_extraction_response["extractionResult"][ + "DocumentId" + ], + "actionTitle": action_title, + "actionPriority": None, + "actionCatalog": None, + "actionFolder": None, + "storageBucketName": None, + "allowChangeOfDocumentType": True, + "storageBucketDirectoryPath": None, + }, + json={"operationId": operation_id}, + ) + + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/du_/api/framework/projects/{project_id}/extractors/{document_type_id}/validation/result/{operation_id}?api-version=1.1", + status_code=200, + match_headers={"X-UiPath-Internal-ConsumptionSourceType": "CodedAgents"}, + json={"status": "Succeeded", "result": create_validation_action_response}, + ) + + modern_extraction_response["projectId"] = project_id + modern_extraction_response["projectType"] = ProjectType.PRETRAINED.value + modern_extraction_response["tag"] = tag + modern_extraction_response["documentTypeId"] = document_type_id + + # ACT + if mode == "async": + response = await service.create_validate_extraction_action_async( + extraction_response=ExtractionResponse.model_validate( + modern_extraction_response + ), + action_title=action_title, + ) + else: + response = service.create_validate_extraction_action( + extraction_response=ExtractionResponse.model_validate( + modern_extraction_response + ), + action_title=action_title, + ) + + # ASSERT + create_validation_action_response["projectId"] = project_id + create_validation_action_response["projectType"] = ProjectType.PRETRAINED.value + create_validation_action_response["tag"] = tag + create_validation_action_response["documentTypeId"] = document_type_id + create_validation_action_response["operationId"] = operation_id + create_validation_action_response["validatedExtractionResults"] = None + create_validation_action_response["dataProjection"] = None + assert response.model_dump() == create_validation_action_response + @pytest.mark.parametrize("mode", ["sync", "async"]) @pytest.mark.asyncio async def test_get_validate_classification_result_pretrained( @@ -2155,6 +2305,71 @@ async def test_start_ixp_extraction_validation( "operationId": operation_id, } + @pytest.mark.parametrize("mode", ["sync", "async"]) + @pytest.mark.asyncio + async def test_start_ixp_extraction_validation_with_optional_params_omitted( + self, + httpx_mock: HTTPXMock, + service: DocumentsService, + base_url: str, + org: str, + tenant: str, + ixp_extraction_response: dict, # type: ignore + mode: str, + ): + # ARRANGE + project_id = str(uuid4()) + operation_id = str(uuid4()) + tag = "live" + action_title = "TestAction" + + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/validation/start?api-version=1.1", + status_code=200, + match_headers={"X-UiPath-Internal-ConsumptionSourceType": "CodedAgents"}, + match_json={ + "extractionResult": ixp_extraction_response["extractionResult"], + "documentId": ixp_extraction_response["extractionResult"]["DocumentId"], + "actionTitle": action_title, + "actionPriority": None, + "actionCatalog": None, + "actionFolder": None, + "storageBucketName": None, + "allowChangeOfDocumentType": True, + "storageBucketDirectoryPath": None, + }, + json={"operationId": operation_id}, + ) + + ixp_extraction_response["projectId"] = project_id + ixp_extraction_response["projectType"] = ProjectType.IXP.value + ixp_extraction_response["tag"] = tag + ixp_extraction_response["documentTypeId"] = str(UUID(int=0)) + + # ACT + if mode == "async": + response = await service.start_ixp_extraction_validation_async( + extraction_response=ExtractionResponse.model_validate( + ixp_extraction_response + ), + action_title=action_title, + ) + else: + response = service.start_ixp_extraction_validation( + extraction_response=ExtractionResponse.model_validate( + ixp_extraction_response + ), + action_title=action_title, + ) + + # ASSERT + assert response.model_dump() == { + "projectId": project_id, + "tag": tag, + "documentId": ixp_extraction_response["extractionResult"]["DocumentId"], + "operationId": operation_id, + } + @pytest.mark.parametrize("mode", ["sync", "async"]) @pytest.mark.asyncio async def test_retrieve_ixp_extraction_validation_result_unassigned( diff --git a/uv.lock b/uv.lock index 9cef98a46..a6f29d735 100644 --- a/uv.lock +++ b/uv.lock @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "uipath" -version = "2.6.12" +version = "2.6.13" source = { editable = "." } dependencies = [ { name = "applicationinsights" },