diff --git a/packages/uipath-platform/pyproject.toml b/packages/uipath-platform/pyproject.toml index c113a5a6b..737a182be 100644 --- a/packages/uipath-platform/pyproject.toml +++ b/packages/uipath-platform/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-platform" -version = "0.1.13" +version = "0.1.14" description = "HTTP client library for programmatic access to UiPath Platform" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/packages/uipath-platform/src/uipath/platform/common/_bindings.py b/packages/uipath-platform/src/uipath/platform/common/_bindings.py index 42d679ad3..cd380ef0c 100644 --- a/packages/uipath-platform/src/uipath/platform/common/_bindings.py +++ b/packages/uipath-platform/src/uipath/platform/common/_bindings.py @@ -44,7 +44,9 @@ def folder_identifier(self) -> str: class GenericResourceOverwrite(ResourceOverwrite): - resource_type: Literal["process", "index", "app", "asset", "bucket", "mcpServer"] + resource_type: Literal[ + "process", "index", "app", "asset", "bucket", "mcpServer", "queue" + ] name: str = Field(alias="name") folder_path: str = Field(alias="folderPath") diff --git a/packages/uipath-platform/src/uipath/platform/orchestrator/_queues_service.py b/packages/uipath-platform/src/uipath/platform/orchestrator/_queues_service.py index 57d0a7ca0..eede00ecf 100644 --- a/packages/uipath-platform/src/uipath/platform/orchestrator/_queues_service.py +++ b/packages/uipath-platform/src/uipath/platform/orchestrator/_queues_service.py @@ -1,12 +1,13 @@ -from typing import Any, Dict, List, Union +from typing import Any, Dict, List, Optional, Union from httpx import Response from uipath.core.tracing import traced from ..common._base_service import BaseService +from ..common._bindings import resource_override from ..common._config import UiPathApiConfig from ..common._execution_context import UiPathExecutionContext -from ..common._folder_context import FolderContext +from ..common._folder_context import FolderContext, header_folder from ..common._models import Endpoint, RequestSpec from .queues import ( CommitType, @@ -28,71 +29,133 @@ def __init__( ) -> None: super().__init__(config=config, execution_context=execution_context) + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_list_items", run_type="uipath") - def list_items(self) -> Response: + def list_items( + self, + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, + ) -> Response: """Retrieves a list of queue items from the Orchestrator. + Args: + queue_name (Optional[str]): The name of the queue to filter items by. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. + Returns: Response: HTTP response containing the list of queue items. """ - spec = self._list_items_spec() - response = self.request(spec.method, url=spec.endpoint) + spec = self._list_items_spec( + queue_name=queue_name, folder_key=folder_key, folder_path=folder_path + ) + response = self.request( + spec.method, url=spec.endpoint, params=spec.params, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_list_items", run_type="uipath") - async def list_items_async(self) -> Response: + async def list_items_async( + self, + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, + ) -> Response: """Asynchronously retrieves a list of queue items from the Orchestrator. + Args: + queue_name (Optional[str]): The name of the queue to filter items by. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. + Returns: Response: HTTP response containing the list of queue items. """ - spec = self._list_items_spec() - response = await self.request_async(spec.method, url=spec.endpoint) + spec = self._list_items_spec( + queue_name=queue_name, folder_key=folder_key, folder_path=folder_path + ) + response = await self.request_async( + spec.method, url=spec.endpoint, params=spec.params, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_item", run_type="uipath") - def create_item(self, item: Union[Dict[str, Any], QueueItem]) -> Response: + def create_item( + self, + item: Union[Dict[str, Any], QueueItem], + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, + ) -> Response: """Creates a new queue item in the Orchestrator. Args: item: Queue item data, either as a dictionary or QueueItem instance. + queue_name (Optional[str]): The name of the queue. Overrides item.name when provided. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the created queue item details. Related Activity: [Add Queue Item](https://docs.uipath.com/ACTIVITIES/other/latest/workflow/add-queue-item) """ - spec = self._create_item_spec(item) - response = self.request(spec.method, url=spec.endpoint, json=spec.json) + spec = self._create_item_spec( + item, queue_name=queue_name, folder_key=folder_key, folder_path=folder_path + ) + response = self.request( + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_item", run_type="uipath") async def create_item_async( - self, item: Union[Dict[str, Any], QueueItem] + self, + item: Union[Dict[str, Any], QueueItem], + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Asynchronously creates a new queue item in the Orchestrator. Args: item: Queue item data, either as a dictionary or QueueItem instance. + queue_name (Optional[str]): The name of the queue. Overrides item.name when provided. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the created queue item details. Related Activity: [Add Queue Item](https://docs.uipath.com/ACTIVITIES/other/latest/workflow/add-queue-item) """ - spec = self._create_item_spec(item) + spec = self._create_item_spec( + item, queue_name=queue_name, folder_key=folder_key, folder_path=folder_path + ) response = await self.request_async( - spec.method, url=spec.endpoint, json=spec.json + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_items", run_type="uipath") def create_items( self, items: List[Union[Dict[str, Any], QueueItem]], queue_name: str, commit_type: CommitType, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Creates multiple queue items in bulk. @@ -100,20 +163,34 @@ def create_items( items: List of queue items to create, each either a dictionary or QueueItem instance. queue_name: Name of the target queue. commit_type: Type of commit operation to use for the bulk operation. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the bulk operation result. """ - spec = self._create_items_spec(items, queue_name, commit_type) - response = self.request(spec.method, url=spec.endpoint, json=spec.json) + spec = self._create_items_spec( + items, + queue_name, + commit_type, + folder_key=folder_key, + folder_path=folder_path, + ) + response = self.request( + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_items", run_type="uipath") async def create_items_async( self, items: List[Union[Dict[str, Any], QueueItem]], queue_name: str, commit_type: CommitType, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Asynchronously creates multiple queue items in bulk. @@ -121,129 +198,223 @@ async def create_items_async( items: List of queue items to create, each either a dictionary or QueueItem instance. queue_name: Name of the target queue. commit_type: Type of commit operation to use for the bulk operation. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the bulk operation result. """ - spec = self._create_items_spec(items, queue_name, commit_type) + spec = self._create_items_spec( + items, + queue_name, + commit_type, + folder_key=folder_key, + folder_path=folder_path, + ) response = await self.request_async( - spec.method, url=spec.endpoint, json=spec.json + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_transaction_item", run_type="uipath") def create_transaction_item( - self, item: Union[Dict[str, Any], TransactionItem], no_robot: bool = False + self, + item: Union[Dict[str, Any], TransactionItem], + queue_name: Optional[str] = None, + no_robot: bool = False, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Creates a new transaction item in a queue. Args: item: Transaction item data, either as a dictionary or TransactionItem instance. + queue_name (Optional[str]): The name of the queue. Overrides item.name when provided. no_robot: If True, the transaction will not be associated with a robot. Defaults to False. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the transaction item details. """ - spec = self._create_transaction_item_spec(item, no_robot) - response = self.request(spec.method, url=spec.endpoint, json=spec.json) + spec = self._create_transaction_item_spec( + item, + queue_name=queue_name, + no_robot=no_robot, + folder_key=folder_key, + folder_path=folder_path, + ) + response = self.request( + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_create_transaction_item", run_type="uipath") async def create_transaction_item_async( - self, item: Union[Dict[str, Any], TransactionItem], no_robot: bool = False + self, + item: Union[Dict[str, Any], TransactionItem], + queue_name: Optional[str] = None, + no_robot: bool = False, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Asynchronously creates a new transaction item in a queue. Args: item: Transaction item data, either as a dictionary or TransactionItem instance. + queue_name (Optional[str]): The name of the queue. Overrides item.name when provided. no_robot: If True, the transaction will not be associated with a robot. Defaults to False. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response containing the transaction item details. """ - spec = self._create_transaction_item_spec(item, no_robot) + spec = self._create_transaction_item_spec( + item, + queue_name=queue_name, + no_robot=no_robot, + folder_key=folder_key, + folder_path=folder_path, + ) response = await self.request_async( - spec.method, url=spec.endpoint, json=spec.json + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_update_progress_of_transaction_item", run_type="uipath") def update_progress_of_transaction_item( - self, transaction_key: str, progress: str + self, + transaction_key: str, + progress: str, + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Updates the progress of a transaction item. Args: transaction_key: Unique identifier of the transaction. progress: Progress message to set. + queue_name (Optional[str]): The name of the queue the transaction belongs to. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response confirming the progress update. Related Activity: [Set Transaction Progress](https://docs.uipath.com/activities/other/latest/workflow/set-transaction-progress) """ - spec = self._update_progress_of_transaction_item_spec(transaction_key, progress) - response = self.request(spec.method, url=spec.endpoint, json=spec.json) + spec = self._update_progress_of_transaction_item_spec( + transaction_key, progress, folder_key=folder_key, folder_path=folder_path + ) + response = self.request( + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_update_progress_of_transaction_item", run_type="uipath") async def update_progress_of_transaction_item_async( - self, transaction_key: str, progress: str + self, + transaction_key: str, + progress: str, + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Asynchronously updates the progress of a transaction item. Args: transaction_key: Unique identifier of the transaction. progress: Progress message to set. + queue_name (Optional[str]): The name of the queue the transaction belongs to. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response confirming the progress update. Related Activity: [Set Transaction Progress](https://docs.uipath.com/activities/other/latest/workflow/set-transaction-progress) """ - spec = self._update_progress_of_transaction_item_spec(transaction_key, progress) + spec = self._update_progress_of_transaction_item_spec( + transaction_key, progress, folder_key=folder_key, folder_path=folder_path + ) response = await self.request_async( - spec.method, url=spec.endpoint, json=spec.json + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_complete_transaction_item", run_type="uipath") def complete_transaction_item( - self, transaction_key: str, result: Union[Dict[str, Any], TransactionItemResult] + self, + transaction_key: str, + result: Union[Dict[str, Any], TransactionItemResult], + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Completes a transaction item with the specified result. Args: transaction_key: Unique identifier of the transaction to complete. result: Result data for the transaction, either as a dictionary or TransactionItemResult instance. + queue_name (Optional[str]): The name of the queue the transaction belongs to. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response confirming the transaction completion. Related Activity: [Set Transaction Status](https://docs.uipath.com/activities/other/latest/workflow/set-transaction-status) """ - spec = self._complete_transaction_item_spec(transaction_key, result) - response = self.request(spec.method, url=spec.endpoint, json=spec.json) + spec = self._complete_transaction_item_spec( + transaction_key, result, folder_key=folder_key, folder_path=folder_path + ) + response = self.request( + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers + ) return response.json() + @resource_override(resource_type="queue", resource_identifier="queue_name") @traced(name="queues_complete_transaction_item", run_type="uipath") async def complete_transaction_item_async( - self, transaction_key: str, result: Union[Dict[str, Any], TransactionItemResult] + self, + transaction_key: str, + result: Union[Dict[str, Any], TransactionItemResult], + queue_name: Optional[str] = None, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> Response: """Asynchronously completes a transaction item with the specified result. Args: transaction_key: Unique identifier of the transaction to complete. result: Result data for the transaction, either as a dictionary or TransactionItemResult instance. + queue_name (Optional[str]): The name of the queue the transaction belongs to. + folder_key (Optional[str]): The key of the folder. Overrides the default one set in the SDK config. + folder_path (Optional[str]): The path of the folder. Overrides the default one set in the SDK config. Returns: Response: HTTP response confirming the transaction completion. Related Activity: [Set Transaction Status](https://docs.uipath.com/activities/other/latest/workflow/set-transaction-status) """ - spec = self._complete_transaction_item_spec(transaction_key, result) + spec = self._complete_transaction_item_spec( + transaction_key, result, folder_key=folder_key, folder_path=folder_path + ) response = await self.request_async( - spec.method, url=spec.endpoint, json=spec.json + spec.method, url=spec.endpoint, json=spec.json, headers=spec.headers ) return response.json() @@ -251,21 +422,47 @@ async def complete_transaction_item_async( def custom_headers(self) -> Dict[str, str]: return self.folder_headers - def _list_items_spec(self) -> RequestSpec: + def _list_items_spec( + self, + *, + queue_name: Optional[str] = None, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, + ) -> RequestSpec: + params = {} + if queue_name is not None: + params["$filter"] = f"QueueDefinitionName eq '{queue_name}'" return RequestSpec( method="GET", endpoint=Endpoint("/orchestrator_/odata/QueueItems"), + params=params, + headers={ + **header_folder(folder_key, folder_path), + }, ) - def _create_item_spec(self, item: Union[Dict[str, Any], QueueItem]) -> RequestSpec: + def _create_item_spec( + self, + item: Union[Dict[str, Any], QueueItem], + *, + queue_name: Optional[str] = None, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, + ) -> RequestSpec: if isinstance(item, dict): queue_item = QueueItem(**item) elif isinstance(item, QueueItem): queue_item = item - json_payload = { - "itemData": queue_item.model_dump(exclude_unset=True, by_alias=True) - } + item_data = queue_item.model_dump(exclude_unset=True, by_alias=True) + resolved_name = queue_name or item_data.get("Name") + if resolved_name is None: + raise ValueError( + "queue_name must be provided either via the queue_name parameter or item.name" + ) + item_data["Name"] = resolved_name + + json_payload = {"itemData": item_data} return RequestSpec( method="POST", @@ -273,6 +470,9 @@ def _create_item_spec(self, item: Union[Dict[str, Any], QueueItem]) -> RequestSp "/orchestrator_/odata/Queues/UiPathODataSvc.AddQueueItem" ), json=json_payload, + headers={ + **header_folder(folder_key, folder_path), + }, ) def _create_items_spec( @@ -280,6 +480,9 @@ def _create_items_spec( items: List[Union[Dict[str, Any], QueueItem]], queue_name: str, commit_type: CommitType, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> RequestSpec: return RequestSpec( method="POST", @@ -296,35 +499,55 @@ def _create_items_spec( for item in items ], }, + headers={ + **header_folder(folder_key, folder_path), + }, ) def _create_transaction_item_spec( - self, item: Union[Dict[str, Any], TransactionItem], no_robot: bool = False + self, + item: Union[Dict[str, Any], TransactionItem], + *, + queue_name: Optional[str] = None, + no_robot: bool = False, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> RequestSpec: if isinstance(item, dict): transaction_item = TransactionItem(**item) elif isinstance(item, TransactionItem): transaction_item = item + transaction_data = transaction_item.model_dump( + exclude_unset=True, by_alias=True + ) + resolved_name = queue_name or transaction_data.get("Name") + if resolved_name is None: + raise ValueError( + "queue_name must be provided either via the queue_name parameter or item.name" + ) + transaction_data["Name"] = resolved_name + if not no_robot: + transaction_data["RobotIdentifier"] = self._execution_context.robot_key + return RequestSpec( method="POST", endpoint=Endpoint( "/orchestrator_/odata/Queues/UiPathODataSvc.StartTransaction" ), - json={ - "transactionData": { - **transaction_item.model_dump(exclude_unset=True, by_alias=True), - **( - {"RobotIdentifier": self._execution_context.robot_key} - if not no_robot - else {} - ), - } + json={"transactionData": transaction_data}, + headers={ + **header_folder(folder_key, folder_path), }, ) def _update_progress_of_transaction_item_spec( - self, transaction_key: str, progress: str + self, + transaction_key: str, + progress: str, + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> RequestSpec: return RequestSpec( method="POST", @@ -332,10 +555,18 @@ def _update_progress_of_transaction_item_spec( f"/orchestrator_/odata/QueueItems({transaction_key})/UiPathODataSvc.SetTransactionProgress" ), json={"progress": progress}, + headers={ + **header_folder(folder_key, folder_path), + }, ) def _complete_transaction_item_spec( - self, transaction_key: str, result: Union[Dict[str, Any], TransactionItemResult] + self, + transaction_key: str, + result: Union[Dict[str, Any], TransactionItemResult], + *, + folder_key: Optional[str] = None, + folder_path: Optional[str] = None, ) -> RequestSpec: if isinstance(result, dict): transaction_result = TransactionItemResult(**result) @@ -352,4 +583,7 @@ def _complete_transaction_item_spec( exclude_unset=True, by_alias=True ) }, + headers={ + **header_folder(folder_key, folder_path), + }, ) diff --git a/packages/uipath-platform/src/uipath/platform/orchestrator/queues.py b/packages/uipath-platform/src/uipath/platform/orchestrator/queues.py index 3acd4a79b..94cc9a6a6 100644 --- a/packages/uipath-platform/src/uipath/platform/orchestrator/queues.py +++ b/packages/uipath-platform/src/uipath/platform/orchestrator/queues.py @@ -1,10 +1,11 @@ """Models for Orchestrator Queues API.""" +import warnings from datetime import datetime from enum import Enum from typing import Any, Dict, Optional -from pydantic import BaseModel, ConfigDict, Field, field_serializer +from pydantic import BaseModel, ConfigDict, Field, field_serializer, model_validator from typing_extensions import Annotated @@ -42,10 +43,24 @@ def serialize_datetime(self, value): return value.isoformat() if value else None return value - name: str = Field( - description="The name of the queue into which the item will be added.", + name: Optional[str] = Field( + default=None, + description="Deprecated: use queue_name on the service method instead. The name of the queue into which the item will be added.", alias="Name", ) + + @model_validator(mode="before") + @classmethod + def warn_name_deprecated(cls, values: Any) -> Any: + """Emit a deprecation warning when the 'name' field is used directly.""" + if isinstance(values, dict) and ("name" in values or "Name" in values): + warnings.warn( + "The 'name' field on QueueItem is deprecated. Pass queue_name to the service method instead.", + DeprecationWarning, + stacklevel=2, + ) + return values + priority: Optional[QueueItemPriority] = Field( default=None, description="Sets the processing importance for a given item.", @@ -113,10 +128,24 @@ def serialize_datetime(self, value): return value.isoformat() if value else None return value - name: str = Field( - description="The name of the queue in which to search for the next item or in which to insert the item before marking it as InProgress and sending it to the robot.", + name: Optional[str] = Field( + default=None, + description="Deprecated: use queue_name on the service method instead. The name of the queue in which to search for the next item or in which to insert the item before marking it as InProgress and sending it to the robot.", alias="Name", ) + + @model_validator(mode="before") + @classmethod + def warn_name_deprecated(cls, values: Any) -> Any: + """Emit a deprecation warning when the 'name' field is used directly.""" + if isinstance(values, dict) and ("name" in values or "Name" in values): + warnings.warn( + "The 'name' field on TransactionItem is deprecated. Pass queue_name to the service method instead.", + DeprecationWarning, + stacklevel=2, + ) + return values + robot_identifier: Optional[str] = Field( default=None, description="The unique key identifying the robot that sent the request.", diff --git a/packages/uipath-platform/tests/services/test_queues_service.py b/packages/uipath-platform/tests/services/test_queues_service.py index a70c27c59..51cfeaa95 100644 --- a/packages/uipath-platform/tests/services/test_queues_service.py +++ b/packages/uipath-platform/tests/services/test_queues_service.py @@ -4,7 +4,11 @@ from pytest_httpx import HTTPXMock from uipath.platform import UiPathApiConfig, UiPathExecutionContext -from uipath.platform.common.constants import HEADER_USER_AGENT +from uipath.platform.common.constants import ( + HEADER_FOLDER_KEY, + HEADER_FOLDER_PATH, + HEADER_USER_AGENT, +) from uipath.platform.orchestrator import ( CommitType, QueueItem, @@ -127,7 +131,6 @@ def test_create_item( version: str, ) -> None: queue_item = QueueItem( - name="test-queue", priority=QueueItemPriority.HIGH, specific_content={"key": "value"}, ) @@ -142,7 +145,7 @@ def test_create_item( }, ) - response = service.create_item(queue_item) + response = service.create_item(queue_item, queue_name="test-queue") assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -183,7 +186,6 @@ async def test_create_item_async( version: str, ) -> None: queue_item = QueueItem( - name="test-queue", priority=QueueItemPriority.HIGH, specific_content={"key": "value"}, ) @@ -198,7 +200,7 @@ async def test_create_item_async( }, ) - response = await service.create_item_async(queue_item) + response = await service.create_item_async(queue_item, queue_name="test-queue") assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -239,12 +241,10 @@ def test_create_items( ) -> None: queue_items = [ QueueItem( - name="test-queue", priority=QueueItemPriority.HIGH, specific_content={"key": "value"}, ), QueueItem( - name="test-queue", priority=QueueItemPriority.LOW, specific_content={"key2": "value2"}, ), @@ -298,12 +298,10 @@ def test_create_items( "commitType": "AllOrNothing", "queueItems": [ { - "Name": "test-queue", "Priority": "High", "SpecificContent": {"key": "value"}, }, { - "Name": "test-queue", "Priority": "Low", "SpecificContent": {"key2": "value2"}, }, @@ -328,12 +326,10 @@ async def test_create_items_async( ) -> None: queue_items = [ QueueItem( - name="test-queue", priority=QueueItemPriority.HIGH, specific_content={"key": "value"}, ), QueueItem( - name="test-queue", priority=QueueItemPriority.LOW, specific_content={"key2": "value2"}, ), @@ -387,12 +383,10 @@ async def test_create_items_async( "commitType": "AllOrNothing", "queueItems": [ { - "Name": "test-queue", "Priority": "High", "SpecificContent": {"key": "value"}, }, { - "Name": "test-queue", "Priority": "Low", "SpecificContent": {"key2": "value2"}, }, @@ -416,7 +410,6 @@ def test_create_item_with_reference( ) -> None: reference_value = "TEST-REF-12345" queue_item = QueueItem( - name="test-queue", reference=reference_value, priority=QueueItemPriority.HIGH, specific_content={"invoice_id": "INV-001"}, @@ -433,7 +426,7 @@ def test_create_item_with_reference( }, ) - response = service.create_item(queue_item) + response = service.create_item(queue_item, queue_name="test-queue") assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -477,7 +470,6 @@ async def test_create_item_with_reference_async( ) -> None: reference_value = "TEST-REF-12345" queue_item = QueueItem( - name="test-queue", reference=reference_value, priority=QueueItemPriority.HIGH, specific_content={"invoice_id": "INV-001"}, @@ -494,7 +486,7 @@ async def test_create_item_with_reference_async( }, ) - response = await service.create_item_async(queue_item) + response = await service.create_item_async(queue_item, queue_name="test-queue") assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -536,7 +528,6 @@ def test_create_transaction_item( version: str, ) -> None: transaction_item = TransactionItem( - name="test-queue", specific_content={"key": "value"}, ) httpx_mock.add_response( @@ -549,7 +540,9 @@ def test_create_transaction_item( }, ) - response = service.create_transaction_item(transaction_item) + response = service.create_transaction_item( + transaction_item, queue_name="test-queue" + ) assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -589,7 +582,6 @@ async def test_create_transaction_item_async( version: str, ) -> None: transaction_item = TransactionItem( - name="test-queue", specific_content={"key": "value"}, ) httpx_mock.add_response( @@ -602,7 +594,9 @@ async def test_create_transaction_item_async( }, ) - response = await service.create_transaction_item_async(transaction_item) + response = await service.create_transaction_item_async( + transaction_item, queue_name="test-queue" + ) assert response["Id"] == 1 assert response["Name"] == "test-queue" @@ -806,3 +800,373 @@ async def test_complete_transaction_item_async( sent_request.headers[HEADER_USER_AGENT] == f"UiPath.Python.Sdk/UiPath.Python.Sdk.Activities.QueuesService.complete_transaction_item_async/{version}" ) + + def test_list_items_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/QueueItems", + status_code=200, + json={"value": []}, + ) + + service.list_items(folder_key="custom-folder-key") + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + def test_list_items_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/QueueItems", + status_code=200, + json={"value": []}, + ) + + service.list_items(folder_path="Custom/Folder/Path") + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" + + @pytest.mark.asyncio + async def test_list_items_async_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/QueueItems", + status_code=200, + json={"value": []}, + ) + + await service.list_items_async(folder_key="custom-folder-key") + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + def test_create_item_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + queue_item = QueueItem( + priority=QueueItemPriority.HIGH, + specific_content={"key": "value"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.AddQueueItem", + status_code=200, + json={"Id": 1}, + ) + + service.create_item( + queue_item, queue_name="test-queue", folder_key="custom-folder-key" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + def test_create_item_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + queue_item = QueueItem( + priority=QueueItemPriority.HIGH, + specific_content={"key": "value"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.AddQueueItem", + status_code=200, + json={"Id": 1}, + ) + + service.create_item( + queue_item, queue_name="test-queue", folder_path="Custom/Folder/Path" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" + + @pytest.mark.asyncio + async def test_create_item_async_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + queue_item = QueueItem( + priority=QueueItemPriority.HIGH, + specific_content={"key": "value"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.AddQueueItem", + status_code=200, + json={"Id": 1}, + ) + + await service.create_item_async( + queue_item, queue_name="test-queue", folder_key="custom-folder-key" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + def test_create_items_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + queue_items = [ + QueueItem( + priority=QueueItemPriority.HIGH, + specific_content={"key": "value"}, + ), + ] + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.BulkAddQueueItems", + status_code=200, + json={"value": []}, + ) + + service.create_items( + queue_items, + "test-queue", + CommitType.ALL_OR_NOTHING, + folder_key="custom-folder-key", + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + @pytest.mark.asyncio + async def test_create_items_async_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + queue_items = [ + QueueItem( + priority=QueueItemPriority.HIGH, + specific_content={"key": "value"}, + ), + ] + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.BulkAddQueueItems", + status_code=200, + json={"value": []}, + ) + + await service.create_items_async( + queue_items, + "test-queue", + CommitType.ALL_OR_NOTHING, + folder_path="Custom/Folder/Path", + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" + + def test_create_transaction_item_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_item = TransactionItem( + specific_content={"key": "value"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.StartTransaction", + status_code=200, + json={"Id": 1}, + ) + + service.create_transaction_item( + transaction_item, queue_name="test-queue", folder_key="custom-folder-key" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + @pytest.mark.asyncio + async def test_create_transaction_item_async_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_item = TransactionItem( + specific_content={"key": "value"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues/UiPathODataSvc.StartTransaction", + status_code=200, + json={"Id": 1}, + ) + + await service.create_transaction_item_async( + transaction_item, queue_name="test-queue", folder_path="Custom/Folder/Path" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" + + def test_update_progress_of_transaction_item_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_key = "test-transaction-key" + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/QueueItems({transaction_key})/UiPathODataSvc.SetTransactionProgress", + status_code=200, + json={"status": "success"}, + ) + + service.update_progress_of_transaction_item( + transaction_key, "Processing...", folder_key="custom-folder-key" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + @pytest.mark.asyncio + async def test_update_progress_of_transaction_item_async_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_key = "test-transaction-key" + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/QueueItems({transaction_key})/UiPathODataSvc.SetTransactionProgress", + status_code=200, + json={"status": "success"}, + ) + + await service.update_progress_of_transaction_item_async( + transaction_key, "Processing...", folder_path="Custom/Folder/Path" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" + + def test_complete_transaction_item_with_folder_key( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_key = "test-transaction-key" + result = TransactionItemResult( + is_successful=True, + output={"result": "success"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues({transaction_key})/UiPathODataSvc.SetTransactionResult", + status_code=200, + json={"status": "success"}, + ) + + service.complete_transaction_item( + transaction_key, result, folder_key="custom-folder-key" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_KEY in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_KEY] == "custom-folder-key" + + @pytest.mark.asyncio + async def test_complete_transaction_item_async_with_folder_path( + self, + httpx_mock: HTTPXMock, + service: QueuesService, + base_url: str, + org: str, + tenant: str, + ) -> None: + transaction_key = "test-transaction-key" + result = TransactionItemResult( + is_successful=True, + output={"result": "success"}, + ) + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/orchestrator_/odata/Queues({transaction_key})/UiPathODataSvc.SetTransactionResult", + status_code=200, + json={"status": "success"}, + ) + + await service.complete_transaction_item_async( + transaction_key, result, folder_path="Custom/Folder/Path" + ) + + sent_request = httpx_mock.get_request() + assert sent_request is not None + assert HEADER_FOLDER_PATH in sent_request.headers + assert sent_request.headers[HEADER_FOLDER_PATH] == "Custom/Folder/Path" diff --git a/packages/uipath-platform/uv.lock b/packages/uipath-platform/uv.lock index 1542a2fb2..67e119a75 100644 --- a/packages/uipath-platform/uv.lock +++ b/packages/uipath-platform/uv.lock @@ -1088,7 +1088,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.13" +version = "0.1.14" source = { editable = "." } dependencies = [ { name = "httpx" }, diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 667a4ac50..56004d204 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2682,7 +2682,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.1.13" +version = "0.1.14" source = { editable = "../uipath-platform" } dependencies = [ { name = "httpx" },