uipath 2.1.111__py3-none-any.whl → 2.1.112__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uipath might be problematic. Click here for more details.

@@ -4,7 +4,7 @@ import logging
4
4
  import os
5
5
  from abc import ABC, abstractmethod
6
6
  from enum import Enum
7
- from typing import Any, Dict, List, Optional, Set
7
+ from typing import Any, Dict, List, Literal, Optional, Set
8
8
 
9
9
  from pydantic import BaseModel
10
10
  from pysignalr.client import SignalRClient
@@ -123,7 +123,7 @@ class UiPathDebugBridge(ABC):
123
123
  pass
124
124
 
125
125
  @abstractmethod
126
- def get_breakpoints(self) -> List[str]:
126
+ def get_breakpoints(self) -> List[str] | Literal["*"]:
127
127
  """Get nodes to suspend execution at.
128
128
 
129
129
  Returns:
@@ -220,7 +220,7 @@ class ConsoleDebugBridge(UiPathDebugBridge):
220
220
  """Print error."""
221
221
  self.console.print()
222
222
  self.console.print("[red]─" * 40)
223
- self.console.print(f"[red]✗ Error[/red] [dim]{execution_id}")
223
+ self.console.print("[red]✗ Error[/red]")
224
224
  self.console.print("[red]─" * 40)
225
225
 
226
226
  # Truncate very long errors
@@ -228,7 +228,7 @@ class ConsoleDebugBridge(UiPathDebugBridge):
228
228
  if len(error) > 500:
229
229
  error_display = error[:500] + "\n[dim]... (truncated)"
230
230
 
231
- self.console.print(f"[white]{error_display}[/white]")
231
+ self.console.print(f"[red]{error_display}[/red]")
232
232
  self.console.print("[red]─" * 40)
233
233
 
234
234
  async def wait_for_resume(self) -> Any:
@@ -252,21 +252,14 @@ class ConsoleDebugBridge(UiPathDebugBridge):
252
252
  # These commands don't resume execution, loop again
253
253
  continue
254
254
 
255
- # Reset step modes if continuing
256
- if command_result["command"] == DebugCommand.CONTINUE:
257
- self.state.step_mode = False
258
-
259
- if command_result["command"] == DebugCommand.QUIT:
260
- raise DebuggerQuitException("User requested exit")
261
-
262
255
  # Commands that resume execution: CONTINUE, STEP
263
256
  self.console.print()
264
257
  return command_result
265
258
 
266
- def get_breakpoints(self) -> List[str]:
259
+ def get_breakpoints(self) -> List[str] | Literal["*"]:
267
260
  """Get nodes to suspend execution at."""
268
261
  if self.state.step_mode:
269
- return ["*"] # Suspend at all nodes
262
+ return "*" # Suspend at all nodes
270
263
  return list(self.state.breakpoints) # Only suspend at breakpoints
271
264
 
272
265
  def _parse_command(self, user_input: str) -> Dict[str, Any]:
@@ -283,6 +276,7 @@ class ConsoleDebugBridge(UiPathDebugBridge):
283
276
  args = parts[1:] if len(parts) > 1 else []
284
277
 
285
278
  if cmd in ["c", "continue"]:
279
+ self.state.step_mode = False
286
280
  return {"command": DebugCommand.CONTINUE, "args": None}
287
281
 
288
282
  elif cmd in ["s", "step"]:
@@ -318,7 +312,7 @@ class ConsoleDebugBridge(UiPathDebugBridge):
318
312
  }
319
313
 
320
314
  elif cmd in ["q", "quit", "exit"]:
321
- raise KeyboardInterrupt("User requested exit")
315
+ raise DebuggerQuitException("User requested exit")
322
316
 
323
317
  elif cmd in ["h", "help", "?"]:
324
318
  self._print_help()
@@ -465,26 +459,75 @@ class SignalRDebugBridge(UiPathDebugBridge):
465
459
  self._client = SignalRClient(self.hub_url, headers=all_headers)
466
460
 
467
461
  # Register event handlers
468
- self._client.on("ResumeExecution", self._handle_resume)
462
+ self._client.on("Start", self._handle_start)
463
+ self._client.on("Resume", self._handle_resume)
464
+ self._client.on("Step", self._handle_step)
465
+ self._client.on("AddBreakpoints", self._handle_add_breakpoints)
466
+ self._client.on("RemoveBreakpoints", self._handle_remove_breakpoints)
467
+ self._client.on("Quit", self._handle_quit)
469
468
  self._client.on_open(self._handle_open)
470
469
  self._client.on_close(self._handle_close)
471
470
  self._client.on_error(self._handle_error)
472
471
 
473
- # Start connection in background
474
- asyncio.create_task(self._client.run())
472
+ self._run_task = asyncio.create_task(self._client.run())
473
+
474
+ async def cleanup_run_task() -> str:
475
+ error_message = (
476
+ "Failed to establish WebSocket connection within 10s timeout"
477
+ )
478
+
479
+ if self._run_task:
480
+ if not self._run_task.done():
481
+ self._run_task.cancel()
482
+ try:
483
+ await self._run_task
484
+ except asyncio.CancelledError:
485
+ pass # Expected on cancel
486
+ except Exception as task_error:
487
+ error_msg = str(task_error).strip()
488
+ error_detail = f": {error_msg}" if error_msg else ""
489
+ return f"{error_message}: {type(task_error).__name__}{error_detail}"
490
+
491
+ return error_message
492
+
493
+ try:
494
+ # Wait for connection with timeout
495
+ await asyncio.wait_for(self._connected_event.wait(), timeout=10.0)
496
+ except asyncio.TimeoutError as e:
497
+ # Clean up on timeout
498
+ raise RuntimeError(await cleanup_run_task()) from e
499
+ except Exception:
500
+ # Clean up on any other error
501
+ await cleanup_run_task()
502
+ raise
475
503
 
476
- # Wait for connection to establish
477
- await asyncio.wait_for(self._connected_event.wait(), timeout=30.0)
504
+ # Check if run_task failed
505
+ if self._run_task.done():
506
+ exception = self._run_task.exception()
507
+ if exception:
508
+ raise exception
478
509
 
479
510
  async def disconnect(self) -> None:
480
511
  """Close SignalR connection."""
481
- if self._client and hasattr(self._client, "_transport"):
482
- transport = self._client._transport
483
- if transport and hasattr(transport, "_ws") and transport._ws:
484
- try:
512
+ if not self._client:
513
+ return
514
+
515
+ # Cancel the run task first
516
+ if self._run_task and not self._run_task.done():
517
+ self._run_task.cancel()
518
+ try:
519
+ await self._run_task
520
+ except (Exception, asyncio.CancelledError):
521
+ pass
522
+
523
+ # Try to close the client cleanly
524
+ try:
525
+ if hasattr(self._client, "_transport"):
526
+ transport = self._client._transport
527
+ if transport and hasattr(transport, "_ws") and transport._ws:
485
528
  await transport._ws.close()
486
- except Exception as e:
487
- logger.warning(f"Error closing SignalR WebSocket: {e}")
529
+ except Exception as e:
530
+ logger.warning(f"Error closing SignalR WebSocket: {e}")
488
531
 
489
532
  async def emit_execution_started(self, execution_id: str, **kwargs) -> None:
490
533
  """Send execution started event."""
@@ -541,6 +584,9 @@ class SignalRDebugBridge(UiPathDebugBridge):
541
584
  error: str,
542
585
  ) -> None:
543
586
  """Send execution error event."""
587
+ if not self._connected_event.is_set():
588
+ return
589
+
544
590
  logger.error(f"Execution error: {execution_id} - {error}")
545
591
  await self._send(
546
592
  "OnExecutionError",
@@ -558,24 +604,139 @@ class SignalRDebugBridge(UiPathDebugBridge):
558
604
  logger.info("Resume command received")
559
605
  return self._resume_data
560
606
 
561
- def get_breakpoints(self) -> List[str]:
607
+ def get_breakpoints(self) -> List[str] | Literal["*"]:
562
608
  """Get nodes to suspend execution at."""
563
609
  if self.state.step_mode:
564
- return ["*"] # Suspend at all nodes
610
+ return "*" # Suspend at all nodes
565
611
  return list(self.state.breakpoints) # Only suspend at breakpoints
566
612
 
567
- async def _send(self, method: str, data: Dict[str, Any]) -> None:
568
- """Send message to SignalR hub."""
613
+ async def _send(self, event_name: str, data: Dict[str, Any]) -> None:
614
+ """Send message to SignalR hub via SendCommand.
615
+
616
+ Args:
617
+ event_name: The event/command name (e.g., "OnExecutionStarted")
618
+ data: The data payload to send
619
+ """
569
620
  if not self._client:
570
621
  raise RuntimeError("SignalR client not connected")
622
+ try:
623
+ # Wrap the event in SendCommand protocol
624
+ # Server expects: SendCommand(event_name, json_string_of_data)
625
+ data_json = json.dumps(data)
626
+ arguments: list[Any] = [event_name, data_json]
627
+ await self._client.send(method="SendCommand", arguments=arguments)
628
+ logger.debug(f"Sent command: {event_name} with data: {data}")
629
+ except Exception as e:
630
+ logger.error(f"Error sending command {event_name} to SignalR hub: {e}")
631
+
632
+ async def _handle_start(self, args: list[Any]) -> None:
633
+ """Handle Start command from SignalR server.
571
634
 
572
- await self._client.send(method=method, arguments=[data])
635
+ Args:
636
+ args: List containing command arguments, typically [dict_with_args]
637
+ """
638
+ logger.info(f"Start command received with args: {args}")
639
+ if not args or len(args) == 0:
640
+ logger.warning("Start command received with empty args.")
641
+ return
642
+
643
+ command_args = args[0] if isinstance(args[0], dict) else {}
644
+ self.state.breakpoints = set(command_args.get("breakpoints", []))
645
+ step_mode = command_args.get("enableStepMode", False)
646
+ self.state.step_mode = step_mode
573
647
 
574
648
  async def _handle_resume(self, args: list[Any]) -> None:
575
- """Handle resume command from SignalR server."""
576
- if self._resume_event and len(args) > 0:
577
- self._resume_data = args[0]
649
+ """Handle Resume command from SignalR server.
650
+
651
+ Args:
652
+ args: List containing command arguments
653
+ """
654
+ logger.info(f"Resume command received with args: {args}")
655
+ command_args = args[0] if args and len(args) > 0 else {}
656
+
657
+ if self._resume_event:
658
+ self._resume_data = command_args
578
659
  self._resume_event.set()
660
+ logger.info("Resume event set")
661
+ else:
662
+ logger.warning("Resume command received but no resume event is waiting")
663
+
664
+ async def _handle_step(self, args: list[Any]) -> None:
665
+ """Handle Step command from SignalR server.
666
+
667
+ Args:
668
+ args: List containing command arguments
669
+ """
670
+ logger.info(f"Step command received with args: {args}")
671
+ self.state.step_mode = True
672
+ logger.info("Step mode enabled")
673
+
674
+ async def _handle_add_breakpoints(self, args: list[Any]) -> None:
675
+ """Handle AddBreakpoints command from SignalR server.
676
+
677
+ Args:
678
+ args: List containing command arguments with breakpoints list
679
+ """
680
+ logger.info(f"AddBreakpoints command received with args: {args}")
681
+ if not args or len(args) == 0:
682
+ logger.warning("AddBreakpoints command received with empty args.")
683
+ return
684
+
685
+ command_args = args[0] if isinstance(args[0], dict) else {}
686
+ break_points = command_args.get("breakpoints", [])
687
+
688
+ for bp in break_points:
689
+ node_name = (
690
+ bp.get("node", {}).get("name")
691
+ if isinstance(bp.get("node"), dict)
692
+ else None
693
+ )
694
+ if node_name:
695
+ self.state.add_breakpoint(node_name)
696
+ logger.info(f"Breakpoint set at: {node_name}")
697
+ else:
698
+ logger.warning(f"Breakpoint command received without node name: {bp}")
699
+
700
+ async def _handle_remove_breakpoints(self, args: list[Any]) -> None:
701
+ """Handle RemoveBreakpoints command from SignalR server.
702
+
703
+ Args:
704
+ args: List containing command arguments with breakpoints list
705
+ """
706
+ logger.info(f"RemoveBreakpoints command received with args: {args}")
707
+ if not args or len(args) == 0:
708
+ self.state.clear_all_breakpoints()
709
+ logger.info("All breakpoints cleared")
710
+ return
711
+
712
+ command_args = args[0] if isinstance(args[0], dict) else {}
713
+ break_points = command_args.get("breakpoints", [])
714
+
715
+ if not break_points:
716
+ self.state.clear_all_breakpoints()
717
+ logger.info("All breakpoints cleared")
718
+ else:
719
+ for bp in break_points:
720
+ node_name = (
721
+ bp.get("node", {}).get("name")
722
+ if isinstance(bp.get("node"), dict)
723
+ else None
724
+ )
725
+ if node_name:
726
+ self.state.remove_breakpoint(node_name)
727
+ logger.info(f"Breakpoint removed: {node_name}")
728
+
729
+ async def _handle_quit(self, args: list[Any]) -> None:
730
+ """Handle Quit command from SignalR server.
731
+
732
+ Args:
733
+ args: List containing command arguments
734
+ """
735
+ if args:
736
+ logger.info(f"Quit command received from server with args: {args}")
737
+ else:
738
+ logger.info("Quit command received from server")
739
+ raise DebuggerQuitException("Quit command received from server")
579
740
 
580
741
  async def _handle_open(self) -> None:
581
742
  """Handle SignalR connection open."""
@@ -35,6 +35,7 @@ class UiPathDebugRuntime(UiPathBaseRuntime, Generic[T, C]):
35
35
  self.context: UiPathRuntimeContext = context
36
36
  self.factory: UiPathRuntimeFactory[T, C] = factory
37
37
  self.debug_bridge: UiPathDebugBridge = debug_bridge
38
+ self.execution_id: str = context.job_id or "default"
38
39
  self._inner_runtime: Optional[T] = None
39
40
 
40
41
  @classmethod
@@ -57,7 +58,7 @@ class UiPathDebugRuntime(UiPathBaseRuntime, Generic[T, C]):
57
58
  raise RuntimeError("Failed to create inner runtime")
58
59
 
59
60
  await self.debug_bridge.emit_execution_started(
60
- execution_id=self.context.job_id or "default"
61
+ execution_id=self.execution_id
61
62
  )
62
63
 
63
64
  # Try to stream events from inner runtime
@@ -78,8 +79,11 @@ class UiPathDebugRuntime(UiPathBaseRuntime, Generic[T, C]):
78
79
 
79
80
  except Exception as e:
80
81
  # Emit execution error
82
+ self.context.result = UiPathRuntimeResult(
83
+ status=UiPathRuntimeStatus.FAULTED,
84
+ )
81
85
  await self.debug_bridge.emit_execution_error(
82
- execution_id=self.context.job_id or "default",
86
+ execution_id=self.execution_id,
83
87
  error=str(e),
84
88
  )
85
89
  raise
@@ -382,7 +382,7 @@ class UiPathRuntimeContext(BaseModel):
382
382
  log_handler: Optional[logging.Handler] = None
383
383
  chat_handler: Optional[UiPathConversationHandler] = None
384
384
  is_conversational: Optional[bool] = None
385
- breakpoints: Optional[List[str]] = None
385
+ breakpoints: Optional[List[str] | Literal["*"]] = None
386
386
 
387
387
  model_config = {"arbitrary_types_allowed": True, "extra": "allow"}
388
388
 
@@ -127,19 +127,19 @@ Documents service
127
127
  # Create a validation 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).
128
128
  sdk.documents.create_validation_action(action_title: str, action_priority: <enum 'ActionPriority, action_catalog: str, action_folder: str, storage_bucket_name: str, storage_bucket_directory_path: str, extraction_response: uipath.models.documents.ExtractionResponse) -> uipath.models.documents.ValidationAction
129
129
 
130
- # Asynchronously create a validation action for a document based on the extraction response.
130
+ # Asynchronous version of the [`create_validation_action`][uipath._services.documents_service.DocumentsService.create_validation_action] method.
131
131
  sdk.documents.create_validation_action_async(action_title: str, action_priority: <enum 'ActionPriority, action_catalog: str, action_folder: str, storage_bucket_name: str, storage_bucket_directory_path: str, extraction_response: uipath.models.documents.ExtractionResponse) -> uipath.models.documents.ValidationAction
132
132
 
133
133
  # Extract predicted data from a document using an IXP project.
134
- sdk.documents.extract(project_name: str, tag: str, file: Union[IO[bytes], bytes, str, NoneType]=None, file_path: Optional[str]=None) -> uipath.models.documents.ExtractionResponse
134
+ sdk.documents.extract(project_name: str, tag: str, file: Union[IO[bytes], bytes, str, NoneType]=None, file_path: Optional[str]=None, project_type: <enum 'ProjectType="IXP", document_type_name: Optional[str]=None) -> typing.Union[uipath.models.documents.ExtractionResponse, uipath.models.documents.ExtractionResponseIXP]
135
135
 
136
- # Asynchronously extract predicted data from a document using an IXP project.
137
- sdk.documents.extract_async(project_name: str, tag: str, file: Union[IO[bytes], bytes, str, NoneType]=None, file_path: Optional[str]=None) -> uipath.models.documents.ExtractionResponse
136
+ # Asynchronously version of the [`extract`][uipath._services.documents_service.DocumentsService.extract] method.
137
+ sdk.documents.extract_async(project_name: str, tag: str, file: Union[IO[bytes], bytes, str, NoneType]=None, file_path: Optional[str]=None, project_type: <enum 'ProjectType="IXP", document_type_name: Optional[str]=None) -> typing.Union[uipath.models.documents.ExtractionResponse, uipath.models.documents.ExtractionResponseIXP]
138
138
 
139
139
  # Get the result of a validation action.
140
140
  sdk.documents.get_validation_result(validation_action: uipath.models.documents.ValidationAction) -> uipath.models.documents.ValidatedResult
141
141
 
142
- # Asynchronously get the result of a validation action.
142
+ # Asynchronous version of the [`get_validation_result`][uipath._services.documents_service.DocumentsService.get_validation_result] method.
143
143
  sdk.documents.get_validation_result_async(validation_action: uipath.models.documents.ValidationAction) -> uipath.models.documents.ValidatedResult
144
144
 
145
145
  ```
@@ -1,7 +1,8 @@
1
1
  import asyncio
2
2
  import time
3
+ from contextlib import nullcontext
3
4
  from pathlib import Path
4
- from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Tuple
5
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Set, Tuple, Union
5
6
  from uuid import UUID
6
7
 
7
8
  from httpx._types import FileContent
@@ -13,6 +14,8 @@ from .._utils import Endpoint
13
14
  from ..models.documents import (
14
15
  ActionPriority,
15
16
  ExtractionResponse,
17
+ ExtractionResponseIXP,
18
+ ProjectType,
16
19
  ValidatedResult,
17
20
  ValidationAction,
18
21
  )
@@ -41,11 +44,13 @@ class DocumentsService(FolderContext, BaseService):
41
44
  "X-UiPath-Internal-ConsumptionSourceType": "CodedAgents",
42
45
  }
43
46
 
44
- def _get_project_id_by_name(self, project_name: str) -> str:
47
+ def _get_project_id_by_name(
48
+ self, project_name: str, project_type: ProjectType
49
+ ) -> str:
45
50
  response = self.request(
46
51
  "GET",
47
52
  url=Endpoint("/du_/api/framework/projects"),
48
- params={"api-version": 1.1, "type": "IXP"},
53
+ params={"api-version": 1.1, "type": project_type.value},
49
54
  headers=self._get_common_headers(),
50
55
  )
51
56
 
@@ -58,11 +63,13 @@ class DocumentsService(FolderContext, BaseService):
58
63
  except StopIteration:
59
64
  raise ValueError(f"Project '{project_name}' not found.") from None
60
65
 
61
- async def _get_project_id_by_name_async(self, project_name: str) -> str:
66
+ async def _get_project_id_by_name_async(
67
+ self, project_name: str, project_type: ProjectType
68
+ ) -> str:
62
69
  response = await self.request_async(
63
70
  "GET",
64
71
  url=Endpoint("/du_/api/framework/projects"),
65
- params={"api-version": 1.1, "type": "IXP"},
72
+ params={"api-version": 1.1, "type": project_type.value},
66
73
  headers=self._get_common_headers(),
67
74
  )
68
75
 
@@ -93,8 +100,10 @@ class DocumentsService(FolderContext, BaseService):
93
100
  )
94
101
  return {tag["name"] for tag in response.json().get("tags", [])}
95
102
 
96
- def _get_project_id_and_validate_tag(self, project_name: str, tag: str) -> str:
97
- project_id = self._get_project_id_by_name(project_name)
103
+ def _get_project_id_and_validate_tag(
104
+ self, project_name: str, project_type: ProjectType, tag: str
105
+ ) -> str:
106
+ project_id = self._get_project_id_by_name(project_name, project_type)
98
107
  tags = self._get_project_tags(project_id)
99
108
  if tag not in tags:
100
109
  raise ValueError(
@@ -104,9 +113,11 @@ class DocumentsService(FolderContext, BaseService):
104
113
  return project_id
105
114
 
106
115
  async def _get_project_id_and_validate_tag_async(
107
- self, project_name: str, tag: str
116
+ self, project_name: str, project_type: ProjectType, tag: str
108
117
  ) -> str:
109
- project_id = await self._get_project_id_by_name_async(project_name)
118
+ project_id = await self._get_project_id_by_name_async(
119
+ project_name, project_type
120
+ )
110
121
  tags = await self._get_project_tags_async(project_id)
111
122
  if tag not in tags:
112
123
  raise ValueError(
@@ -147,16 +158,71 @@ class DocumentsService(FolderContext, BaseService):
147
158
  )
148
159
  ).json()["documentId"]
149
160
 
161
+ def _get_document_type_id(
162
+ self,
163
+ project_id: str,
164
+ document_type_name: Optional[str],
165
+ project_type: ProjectType,
166
+ ) -> str:
167
+ if project_type == ProjectType.IXP:
168
+ return str(UUID(int=0))
169
+
170
+ response = self.request(
171
+ "GET",
172
+ url=Endpoint(f"/du_/api/framework/projects/{project_id}/document-types"),
173
+ params={"api-version": 1.1},
174
+ headers=self._get_common_headers(),
175
+ )
176
+
177
+ try:
178
+ return next(
179
+ extractor["id"]
180
+ for extractor in response.json().get("documentTypes", [])
181
+ if extractor["name"].lower() == document_type_name.lower() # type: ignore
182
+ )
183
+ except StopIteration:
184
+ raise ValueError(
185
+ f"Document type '{document_type_name}' not found."
186
+ ) from None
187
+
188
+ async def _get_document_type_id_async(
189
+ self,
190
+ project_id: str,
191
+ document_type_name: Optional[str],
192
+ project_type: ProjectType,
193
+ ) -> str:
194
+ if project_type == ProjectType.IXP:
195
+ return str(UUID(int=0))
196
+
197
+ response = await self.request_async(
198
+ "GET",
199
+ url=Endpoint(f"/du_/api/framework/projects/{project_id}/document-types"),
200
+ params={"api-version": 1.1},
201
+ headers=self._get_common_headers(),
202
+ )
203
+
204
+ try:
205
+ return next(
206
+ extractor["id"]
207
+ for extractor in response.json().get("documentTypes", [])
208
+ if extractor["name"].lower() == document_type_name.lower() # type: ignore
209
+ )
210
+ except StopIteration:
211
+ raise ValueError(
212
+ f"Document type '{document_type_name}' not found."
213
+ ) from None
214
+
150
215
  def _start_extraction(
151
216
  self,
152
217
  project_id: str,
153
218
  tag: str,
219
+ document_type_id: str,
154
220
  document_id: str,
155
221
  ) -> str:
156
222
  return self.request(
157
223
  "POST",
158
224
  url=Endpoint(
159
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/extraction/start"
225
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/extraction/start"
160
226
  ),
161
227
  params={"api-version": 1.1},
162
228
  headers=self._get_common_headers(),
@@ -167,13 +233,14 @@ class DocumentsService(FolderContext, BaseService):
167
233
  self,
168
234
  project_id: str,
169
235
  tag: str,
236
+ document_type_id: str,
170
237
  document_id: str,
171
238
  ) -> str:
172
239
  return (
173
240
  await self.request_async(
174
241
  "POST",
175
242
  url=Endpoint(
176
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/extraction/start"
243
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/extraction/start"
177
244
  ),
178
245
  params={"api-version": 1.1},
179
246
  headers=self._get_common_headers(),
@@ -183,7 +250,7 @@ class DocumentsService(FolderContext, BaseService):
183
250
 
184
251
  def _wait_for_operation(
185
252
  self,
186
- result_getter: Callable[[], Tuple[str, Any]],
253
+ result_getter: Callable[[], Tuple[Any, Optional[Any], Optional[Any]]],
187
254
  wait_statuses: List[str],
188
255
  success_status: str,
189
256
  ) -> Any:
@@ -195,19 +262,23 @@ class DocumentsService(FolderContext, BaseService):
195
262
  status in wait_statuses
196
263
  and (time.monotonic() - start_time) < POLLING_TIMEOUT
197
264
  ):
198
- status, result = result_getter()
265
+ status, error, result = result_getter()
199
266
  time.sleep(POLLING_INTERVAL)
200
267
 
201
268
  if status != success_status:
202
269
  if time.monotonic() - start_time >= POLLING_TIMEOUT:
203
270
  raise TimeoutError("Operation timed out.")
204
- raise RuntimeError(f"Operation failed with status: {status}")
271
+ raise RuntimeError(
272
+ f"Operation failed with status: {status}, error: {error}"
273
+ )
205
274
 
206
275
  return result
207
276
 
208
277
  async def _wait_for_operation_async(
209
278
  self,
210
- result_getter: Callable[[], Awaitable[Tuple[str, Any]]],
279
+ result_getter: Callable[
280
+ [], Awaitable[Tuple[Any, Optional[Any], Optional[Any]]]
281
+ ],
211
282
  wait_statuses: List[str],
212
283
  success_status: str,
213
284
  ) -> Any:
@@ -219,55 +290,80 @@ class DocumentsService(FolderContext, BaseService):
219
290
  status in wait_statuses
220
291
  and (time.monotonic() - start_time) < POLLING_TIMEOUT
221
292
  ):
222
- status, result = await result_getter()
293
+ status, error, result = await result_getter()
223
294
  await asyncio.sleep(POLLING_INTERVAL)
224
295
 
225
296
  if status != success_status:
226
297
  if time.monotonic() - start_time >= POLLING_TIMEOUT:
227
298
  raise TimeoutError("Operation timed out.")
228
- raise RuntimeError(f"Operation failed with status: {status}")
299
+ raise RuntimeError(
300
+ f"Operation failed with status: {status}, error: {error}"
301
+ )
229
302
 
230
303
  return result
231
304
 
232
305
  def _wait_for_extraction(
233
- self, project_id: str, tag: str, operation_id: str
234
- ) -> ExtractionResponse:
235
- extraction_response = self._wait_for_operation(
236
- result_getter=lambda: (
237
- (
238
- result := self.request(
239
- method="GET",
240
- url=Endpoint(
241
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/extraction/result/{operation_id}"
242
- ),
243
- params={"api-version": 1.1},
244
- headers=self._get_common_headers(),
245
- ).json()
246
- )["status"],
306
+ self,
307
+ project_id: str,
308
+ tag: str,
309
+ document_type_id: str,
310
+ operation_id: str,
311
+ project_type: ProjectType,
312
+ ) -> Union[ExtractionResponse, ExtractionResponseIXP]:
313
+ def result_getter() -> Tuple[str, str, Any]:
314
+ result = self.request(
315
+ method="GET",
316
+ url=Endpoint(
317
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/extraction/result/{operation_id}"
318
+ ),
319
+ params={"api-version": 1.1},
320
+ headers=self._get_common_headers(),
321
+ ).json()
322
+ return (
323
+ result["status"],
324
+ result.get("error", None),
247
325
  result.get("result", None),
248
- ),
326
+ )
327
+
328
+ extraction_response = self._wait_for_operation(
329
+ result_getter=result_getter,
249
330
  wait_statuses=["NotStarted", "Running"],
250
331
  success_status="Succeeded",
251
332
  )
252
333
 
253
334
  extraction_response["projectId"] = project_id
254
335
  extraction_response["tag"] = tag
336
+ extraction_response["documentTypeId"] = document_type_id
337
+
338
+ if project_type == ProjectType.IXP:
339
+ return ExtractionResponseIXP.model_validate(extraction_response)
340
+
255
341
  return ExtractionResponse.model_validate(extraction_response)
256
342
 
257
343
  async def _wait_for_extraction_async(
258
- self, project_id: str, tag: str, operation_id: str
259
- ) -> ExtractionResponse:
260
- async def result_getter() -> Tuple[str, Any]:
261
- result = await self.request_async(
262
- method="GET",
263
- url=Endpoint(
264
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/extraction/result/{operation_id}"
265
- ),
266
- params={"api-version": 1.1},
267
- headers=self._get_common_headers(),
344
+ self,
345
+ project_id: str,
346
+ tag: str,
347
+ document_type_id: str,
348
+ operation_id: str,
349
+ project_type: ProjectType,
350
+ ) -> Union[ExtractionResponse, ExtractionResponseIXP]:
351
+ async def result_getter() -> Tuple[str, str, Any]:
352
+ result = (
353
+ await self.request_async(
354
+ method="GET",
355
+ url=Endpoint(
356
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/extraction/result/{operation_id}"
357
+ ),
358
+ params={"api-version": 1.1},
359
+ headers=self._get_common_headers(),
360
+ )
361
+ ).json()
362
+ return (
363
+ result["status"],
364
+ result.get("error", None),
365
+ result.get("result", None),
268
366
  )
269
- json_result = result.json()
270
- return json_result["status"], json_result.get("result", None)
271
367
 
272
368
  extraction_response = await self._wait_for_operation_async(
273
369
  result_getter=result_getter,
@@ -277,6 +373,11 @@ class DocumentsService(FolderContext, BaseService):
277
373
 
278
374
  extraction_response["projectId"] = project_id
279
375
  extraction_response["tag"] = tag
376
+ extraction_response["documentTypeId"] = document_type_id
377
+
378
+ if project_type == ProjectType.IXP:
379
+ return ExtractionResponseIXP.model_validate(extraction_response)
380
+
280
381
  return ExtractionResponse.model_validate(extraction_response)
281
382
 
282
383
  @traced(name="documents_extract", run_type="uipath")
@@ -286,14 +387,18 @@ class DocumentsService(FolderContext, BaseService):
286
387
  tag: str,
287
388
  file: Optional[FileContent] = None,
288
389
  file_path: Optional[str] = None,
289
- ) -> ExtractionResponse:
390
+ project_type: ProjectType = ProjectType.IXP,
391
+ document_type_name: Optional[str] = None,
392
+ ) -> Union[ExtractionResponse, ExtractionResponseIXP]:
290
393
  """Extract predicted data from a document using an IXP project.
291
394
 
292
395
  Args:
293
- project_name (str): Name of the IXP project. Details about IXP projects can be found in the [official documentation](https://docs.uipath.com/ixp/automation-cloud/latest/overview/managing-projects#creating-a-new-project).
396
+ project_name (str): Name of the [IXP](https://docs.uipath.com/ixp/automation-cloud/latest/overview/managing-projects#creating-a-new-project)/[DU Modern](https://docs.uipath.com/document-understanding/automation-cloud/latest/user-guide/about-document-understanding) project.
294
397
  tag (str): Tag of the published project version.
295
398
  file (FileContent, optional): The document file to be processed.
296
399
  file_path (str, optional): Path to the document file to be processed.
400
+ project_type (ProjectType, optional): Type of the project. Defaults to `ProjectType.IXP`.
401
+ document_type_name (str, optional): Document type name associated with the extractor to be used for extraction. Required if `project_type` is `ProjectType.MODERN`.
297
402
 
298
403
  Note:
299
404
  Either `file` or `file_path` must be provided, but not both.
@@ -302,38 +407,63 @@ class DocumentsService(FolderContext, BaseService):
302
407
  ExtractionResponse: The extraction result containing predicted data.
303
408
 
304
409
  Examples:
410
+ IXP projects:
305
411
  ```python
306
412
  with open("path/to/document.pdf", "rb") as file:
307
413
  extraction_response = service.extract(
308
- project_name="MyProject",
414
+ project_name="MyIXPProjectName",
309
415
  tag="live",
310
416
  file=file,
311
417
  )
312
418
  ```
419
+
420
+ DU Modern projects:
421
+ ```python
422
+ with open("path/to/document.pdf", "rb") as file:
423
+ extraction_response = service.extract(
424
+ project_name="MyModernProjectName",
425
+ tag="Production",
426
+ file=file,
427
+ project_type=ProjectType.MODERN,
428
+ document_type_name="Receipts",
429
+ )
430
+ ```
313
431
  """
314
432
  if file is None and file_path is None:
315
433
  raise ValueError("Either `file` or `file_path` must be provided")
316
434
  if file is not None and file_path is not None:
317
435
  raise ValueError("`file` and `file_path` are mutually exclusive")
436
+ if project_type == ProjectType.MODERN and document_type_name is None:
437
+ raise ValueError(
438
+ "`document_type_name` must be provided when `project_type` is `ProjectType.MODERN`"
439
+ )
318
440
 
319
441
  project_id = self._get_project_id_and_validate_tag(
320
- project_name=project_name, tag=tag
442
+ project_name=project_name, project_type=project_type, tag=tag
321
443
  )
322
444
 
323
- if file_path is not None:
324
- with open(Path(file_path), "rb") as handle:
325
- document_id = self._start_digitization(
326
- project_id=project_id, file=handle
327
- )
328
- else:
329
- document_id = self._start_digitization(project_id=project_id, file=file) # type: ignore
445
+ with open(Path(file_path), "rb") if file_path else nullcontext(file) as handle:
446
+ document_id = self._start_digitization(project_id=project_id, file=handle) # type: ignore
447
+
448
+ document_type_id = self._get_document_type_id(
449
+ project_id=project_id,
450
+ document_type_name=document_type_name,
451
+ project_type=project_type,
452
+ )
330
453
 
331
454
  operation_id = self._start_extraction(
332
- project_id=project_id, tag=tag, document_id=document_id
455
+ project_id=project_id,
456
+ tag=tag,
457
+ document_type_id=document_type_id,
458
+ document_id=document_id,
333
459
  )
334
460
 
335
461
  return self._wait_for_extraction(
336
- project_id=project_id, tag=tag, operation_id=operation_id
462
+ project_id=project_id,
463
+ tag=tag,
464
+ document_type_id=document_type_id,
465
+ operation_id=operation_id,
466
+ project_type=project_type,
337
467
  )
338
468
 
339
469
  @traced(name="documents_extract_async", run_type="uipath")
@@ -343,40 +473,55 @@ class DocumentsService(FolderContext, BaseService):
343
473
  tag: str,
344
474
  file: Optional[FileContent] = None,
345
475
  file_path: Optional[str] = None,
346
- ) -> ExtractionResponse:
347
- """Asynchronously extract predicted data from a document using an IXP project."""
476
+ project_type: ProjectType = ProjectType.IXP,
477
+ document_type_name: Optional[str] = None,
478
+ ) -> Union[ExtractionResponse, ExtractionResponseIXP]:
479
+ """Asynchronously version of the [`extract`][uipath._services.documents_service.DocumentsService.extract] method."""
348
480
  if file is None and file_path is None:
349
481
  raise ValueError("Either `file` or `file_path` must be provided")
350
482
  if file is not None and file_path is not None:
351
483
  raise ValueError("`file` and `file_path` are mutually exclusive")
484
+ if project_type == ProjectType.MODERN and document_type_name is None:
485
+ raise ValueError(
486
+ "`document_type_name` must be provided when `project_type` is `ProjectType.MODERN`"
487
+ )
352
488
 
353
489
  project_id = await self._get_project_id_and_validate_tag_async(
354
- project_name=project_name, tag=tag
490
+ project_name=project_name, project_type=project_type, tag=tag
355
491
  )
356
492
 
357
- if file_path is not None:
358
- with open(Path(file_path), "rb") as handle:
359
- document_id = await self._start_digitization_async(
360
- project_id=project_id, file=handle
361
- )
362
- else:
493
+ with open(Path(file_path), "rb") if file_path else nullcontext(file) as handle:
363
494
  document_id = await self._start_digitization_async(
364
495
  project_id=project_id,
365
- file=file, # type: ignore
496
+ file=handle, # type: ignore
366
497
  )
367
498
 
499
+ document_type_id = await self._get_document_type_id_async(
500
+ project_id=project_id,
501
+ document_type_name=document_type_name,
502
+ project_type=project_type,
503
+ )
504
+
368
505
  operation_id = await self._start_extraction_async(
369
- project_id=project_id, tag=tag, document_id=document_id
506
+ project_id=project_id,
507
+ tag=tag,
508
+ document_type_id=document_type_id,
509
+ document_id=document_id,
370
510
  )
371
511
 
372
512
  return await self._wait_for_extraction_async(
373
- project_id=project_id, tag=tag, operation_id=operation_id
513
+ project_id=project_id,
514
+ tag=tag,
515
+ document_type_id=document_type_id,
516
+ operation_id=operation_id,
517
+ project_type=project_type,
374
518
  )
375
519
 
376
520
  def _start_validation(
377
521
  self,
378
522
  project_id: str,
379
523
  tag: str,
524
+ document_type_id: str,
380
525
  action_title: str,
381
526
  action_priority: ActionPriority,
382
527
  action_catalog: str,
@@ -388,7 +533,7 @@ class DocumentsService(FolderContext, BaseService):
388
533
  return self.request(
389
534
  "POST",
390
535
  url=Endpoint(
391
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/validation/start"
536
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/validation/start"
392
537
  ),
393
538
  params={"api-version": 1.1},
394
539
  headers=self._get_common_headers(),
@@ -409,6 +554,7 @@ class DocumentsService(FolderContext, BaseService):
409
554
  self,
410
555
  project_id: str,
411
556
  tag: str,
557
+ document_type_id: str,
412
558
  action_title: str,
413
559
  action_priority: ActionPriority,
414
560
  action_catalog: str,
@@ -421,7 +567,7 @@ class DocumentsService(FolderContext, BaseService):
421
567
  await self.request_async(
422
568
  "POST",
423
569
  url=Endpoint(
424
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/validation/start"
570
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/validation/start"
425
571
  ),
426
572
  params={"api-version": 1.1},
427
573
  headers=self._get_common_headers(),
@@ -440,25 +586,25 @@ class DocumentsService(FolderContext, BaseService):
440
586
  ).json()["operationId"]
441
587
 
442
588
  def _get_validation_result(
443
- self, project_id: str, tag: str, operation_id: str
589
+ self, project_id: str, tag: str, document_type_id: str, operation_id: str
444
590
  ) -> Dict: # type: ignore
445
591
  return self.request(
446
592
  method="GET",
447
593
  url=Endpoint(
448
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/validation/result/{operation_id}"
594
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/validation/result/{operation_id}"
449
595
  ),
450
596
  params={"api-version": 1.1},
451
597
  headers=self._get_common_headers(),
452
598
  ).json()
453
599
 
454
600
  async def _get_validation_result_async(
455
- self, project_id: str, tag: str, operation_id: str
601
+ self, project_id: str, tag: str, document_type_id: str, operation_id: str
456
602
  ) -> Dict: # type: ignore
457
603
  return (
458
604
  await self.request_async(
459
605
  method="GET",
460
606
  url=Endpoint(
461
- f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{UUID(int=0)}/validation/result/{operation_id}"
607
+ f"/du_/api/framework/projects/{project_id}/{tag}/document-types/{document_type_id}/validation/result/{operation_id}"
462
608
  ),
463
609
  params={"api-version": 1.1},
464
610
  headers=self._get_common_headers(),
@@ -466,43 +612,58 @@ class DocumentsService(FolderContext, BaseService):
466
612
  ).json()
467
613
 
468
614
  def _wait_for_create_validation_action(
469
- self, project_id: str, tag: str, operation_id: str
615
+ self, project_id: str, tag: str, document_type_id: str, operation_id: str
470
616
  ) -> ValidationAction:
471
- response = self._wait_for_operation(
472
- lambda: (
473
- (
474
- result := self._get_validation_result(
475
- project_id=project_id, tag=tag, operation_id=operation_id
476
- )
477
- )["status"],
617
+ def result_getter() -> Tuple[Any, Optional[Any], Optional[Any]]:
618
+ result = self._get_validation_result(
619
+ project_id=project_id,
620
+ tag=tag,
621
+ document_type_id=document_type_id,
622
+ operation_id=operation_id,
623
+ )
624
+ return (
625
+ result["status"],
626
+ result.get("error", None),
478
627
  result.get("result", None),
479
- ),
628
+ )
629
+
630
+ response = self._wait_for_operation(
631
+ result_getter=result_getter,
480
632
  wait_statuses=["NotStarted", "Running"],
481
633
  success_status="Succeeded",
482
634
  )
483
635
 
484
636
  response["projectId"] = project_id
485
637
  response["tag"] = tag
638
+ response["documentTypeId"] = document_type_id
486
639
  response["operationId"] = operation_id
487
640
  return ValidationAction.model_validate(response)
488
641
 
489
642
  async def _wait_for_create_validation_action_async(
490
- self, project_id: str, tag: str, operation_id: str
643
+ self, project_id: str, tag: str, document_type_id: str, operation_id: str
491
644
  ) -> ValidationAction:
492
- async def result_getter() -> Tuple[str, Any]:
645
+ async def result_getter_async() -> Tuple[Any, Optional[Any], Optional[Any]]:
493
646
  result = await self._get_validation_result_async(
494
- project_id=project_id, tag=tag, operation_id=operation_id
647
+ project_id=project_id,
648
+ tag=tag,
649
+ document_type_id=document_type_id,
650
+ operation_id=operation_id,
651
+ )
652
+ return (
653
+ result["status"],
654
+ result.get("error", None),
655
+ result.get("result", None),
495
656
  )
496
- return result["status"], result.get("result", None)
497
657
 
498
658
  response = await self._wait_for_operation_async(
499
- result_getter=result_getter,
659
+ result_getter=result_getter_async,
500
660
  wait_statuses=["NotStarted", "Running"],
501
661
  success_status="Succeeded",
502
662
  )
503
663
 
504
664
  response["projectId"] = project_id
505
665
  response["tag"] = tag
666
+ response["documentTypeId"] = document_type_id
506
667
  response["operationId"] = operation_id
507
668
  return ValidationAction.model_validate(response)
508
669
 
@@ -546,7 +707,8 @@ class DocumentsService(FolderContext, BaseService):
546
707
  """
547
708
  operation_id = self._start_validation(
548
709
  project_id=extraction_response.project_id,
549
- tag=extraction_response.tag, # should I validate tag again?
710
+ tag=extraction_response.tag,
711
+ document_type_id=extraction_response.document_type_id,
550
712
  action_title=action_title,
551
713
  action_priority=action_priority,
552
714
  action_catalog=action_catalog,
@@ -559,6 +721,7 @@ class DocumentsService(FolderContext, BaseService):
559
721
  return self._wait_for_create_validation_action(
560
722
  project_id=extraction_response.project_id,
561
723
  tag=extraction_response.tag,
724
+ document_type_id=extraction_response.document_type_id,
562
725
  operation_id=operation_id,
563
726
  )
564
727
 
@@ -573,11 +736,11 @@ class DocumentsService(FolderContext, BaseService):
573
736
  storage_bucket_directory_path: str,
574
737
  extraction_response: ExtractionResponse,
575
738
  ) -> ValidationAction:
576
- """Asynchronously create a validation action for a document based on the extraction response."""
577
- # Add reference to sync method docstring
739
+ """Asynchronous version of the [`create_validation_action`][uipath._services.documents_service.DocumentsService.create_validation_action] method."""
578
740
  operation_id = await self._start_validation_async(
579
741
  project_id=extraction_response.project_id,
580
- tag=extraction_response.tag, # should I validate tag again?
742
+ tag=extraction_response.tag,
743
+ document_type_id=extraction_response.document_type_id,
581
744
  action_title=action_title,
582
745
  action_priority=action_priority,
583
746
  action_catalog=action_catalog,
@@ -590,6 +753,7 @@ class DocumentsService(FolderContext, BaseService):
590
753
  return await self._wait_for_create_validation_action_async(
591
754
  project_id=extraction_response.project_id,
592
755
  tag=extraction_response.tag,
756
+ document_type_id=extraction_response.document_type_id,
593
757
  operation_id=operation_id,
594
758
  )
595
759
 
@@ -613,17 +777,22 @@ class DocumentsService(FolderContext, BaseService):
613
777
  validated_result = service.get_validation_result(validation_action)
614
778
  ```
615
779
  """
616
- response = self._wait_for_operation(
617
- result_getter=lambda: (
618
- (
619
- result := self._get_validation_result(
620
- project_id=validation_action.project_id,
621
- tag=validation_action.tag,
622
- operation_id=validation_action.operation_id,
623
- )
624
- )["result"]["actionStatus"],
780
+
781
+ def result_getter() -> Tuple[str, None, Any]:
782
+ result = self._get_validation_result(
783
+ project_id=validation_action.project_id,
784
+ tag=validation_action.tag,
785
+ document_type_id=validation_action.document_type_id,
786
+ operation_id=validation_action.operation_id,
787
+ )
788
+ return (
789
+ result["result"]["actionStatus"],
790
+ None,
625
791
  result["result"].get("validatedExtractionResults", None),
626
- ),
792
+ )
793
+
794
+ response = self._wait_for_operation(
795
+ result_getter=result_getter,
627
796
  wait_statuses=["Unassigned", "Pending"],
628
797
  success_status="Completed",
629
798
  )
@@ -634,16 +803,19 @@ class DocumentsService(FolderContext, BaseService):
634
803
  async def get_validation_result_async(
635
804
  self, validation_action: ValidationAction
636
805
  ) -> ValidatedResult:
637
- """Asynchronously get the result of a validation action."""
806
+ """Asynchronous version of the [`get_validation_result`][uipath._services.documents_service.DocumentsService.get_validation_result] method."""
638
807
 
639
- async def result_getter() -> Tuple[str, Any]:
808
+ async def result_getter() -> Tuple[str, None, Any]:
640
809
  result = await self._get_validation_result_async(
641
810
  project_id=validation_action.project_id,
642
811
  tag=validation_action.tag,
812
+ document_type_id=validation_action.document_type_id,
643
813
  operation_id=validation_action.operation_id,
644
814
  )
645
- return result["result"]["actionStatus"], result["result"].get(
646
- "validatedExtractionResults", None
815
+ return (
816
+ result["result"]["actionStatus"],
817
+ None,
818
+ result["result"].get("validatedExtractionResults", None),
647
819
  )
648
820
 
649
821
  response = await self._wait_for_operation_async(
@@ -18,10 +18,25 @@ class FieldType(str, Enum):
18
18
 
19
19
 
20
20
  class ActionPriority(str, Enum):
21
+ """Priority levels for validation actions. More details can be found in the [official documentation](https://docs.uipath.com/action-center/automation-cloud/latest/user-guide/create-document-validation-action#configuration)."""
22
+
21
23
  LOW = "Low"
24
+ """Low priority"""
22
25
  MEDIUM = "Medium"
26
+ """Medium priority"""
23
27
  HIGH = "High"
28
+ """High priority"""
24
29
  CRITICAL = "Critical"
30
+ """Critical priority"""
31
+
32
+
33
+ class ProjectType(str, Enum):
34
+ """Project types available and supported by Documents Service."""
35
+
36
+ IXP = "IXP"
37
+ """Represents an [IXP](https://docs.uipath.com/ixp/automation-cloud/latest/overview/managing-projects#creating-a-new-project) project type."""
38
+ MODERN = "Modern"
39
+ """Represents a [DU Modern](https://docs.uipath.com/document-understanding/automation-cloud/latest/user-guide/about-document-understanding) project type."""
25
40
 
26
41
 
27
42
  class FieldValueProjection(BaseModel):
@@ -71,9 +86,9 @@ class ExtractionResponse(BaseModel):
71
86
 
72
87
  Attributes:
73
88
  extraction_result (ExtractionResult): The result of the extraction process.
74
- data_projection (List[FieldGroupValueProjection]): A simplified projection of the extracted data.
75
89
  project_id (str): The ID of the project associated with the extraction.
76
90
  tag (str): The tag associated with the published model version.
91
+ document_type_id (str): The ID of the document type associated with the extraction.
77
92
  """
78
93
 
79
94
  model_config = ConfigDict(
@@ -82,9 +97,19 @@ class ExtractionResponse(BaseModel):
82
97
  )
83
98
 
84
99
  extraction_result: ExtractionResult = Field(alias="extractionResult")
85
- data_projection: List[FieldGroupValueProjection] = Field(alias="dataProjection")
86
100
  project_id: str = Field(alias="projectId")
87
101
  tag: str
102
+ document_type_id: str = Field(alias="documentTypeId")
103
+
104
+
105
+ class ExtractionResponseIXP(ExtractionResponse):
106
+ """A model representing the response from a document extraction process for IXP projects.
107
+
108
+ Attributes:
109
+ data_projection (List[FieldGroupValueProjection]): A simplified projection of the extracted data.
110
+ """
111
+
112
+ data_projection: List[FieldGroupValueProjection] = Field(alias="dataProjection")
88
113
 
89
114
 
90
115
  class ValidationAction(BaseModel):
@@ -107,6 +132,7 @@ class ValidationAction(BaseModel):
107
132
  action_status: str = Field(alias="actionStatus")
108
133
  project_id: str = Field(alias="projectId")
109
134
  tag: str
135
+ document_type_id: str = Field(alias="documentTypeId")
110
136
  operation_id: str = Field(alias="operationId")
111
137
 
112
138
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.1.111
3
+ Version: 2.1.112
4
4
  Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
5
5
  Project-URL: Homepage, https://uipath.com
6
6
  Project-URL: Repository, https://github.com/UiPath/uipath-python
@@ -34,8 +34,8 @@ uipath/_cli/_auth/auth_config.json,sha256=o8J5BBFwiEtjZLHpJ_64lvnTeYeRIHaJ-Bhg0Q
34
34
  uipath/_cli/_auth/index.html,sha256=uGK0CDTP8Rys_p4O_Pbd2x4tz0frKNVcumjrXnal5Nc,22814
35
35
  uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
36
36
  uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
37
- uipath/_cli/_debug/_bridge.py,sha256=_CArFkZlwBYUkmpfqehcXyPNVDXv00vPNFfKJiOVJoA,22269
38
- uipath/_cli/_debug/_runtime.py,sha256=iQ0L7WVvh0eF85D6sckZTTjE5wc_KQjCncT23hEdC6k,5596
37
+ uipath/_cli/_debug/_bridge.py,sha256=iF3lI73TRyVvQDf7Zb-HUxrVrW5oAnWOPT7JIFkFL_I,28433
38
+ uipath/_cli/_debug/_runtime.py,sha256=cGWoyQwHaKG5EQhYqTQfIuCX--n4PBijZQ9iXiOpRIc,5748
39
39
  uipath/_cli/_dev/_terminal/__init__.py,sha256=di_RiN9Mcp9wqyKRRqXag28vbSw8_78mCnQZNn9H-Ss,14027
40
40
  uipath/_cli/_dev/_terminal/_components/_chat.py,sha256=NLRoy49QScHiI-q0FGykkaU8ajv1d23fx7issSALcFA,4119
41
41
  uipath/_cli/_dev/_terminal/_components/_details.py,sha256=FbLYtJ56gqHV6CIrpzO_n9Sk_YNg4nzRKTSsbj-DBPQ,17257
@@ -72,7 +72,7 @@ uipath/_cli/_evals/mocks/mockito_mocker.py,sha256=opwfELnvuh3krnPAg0MupkHTEmhCpQ
72
72
  uipath/_cli/_evals/mocks/mocks.py,sha256=IrvhtTtIuU5geopvCRglNhxKoOcChnnjQZMoYygx0PU,2225
73
73
  uipath/_cli/_push/models.py,sha256=K3k6QUMkiNIb3M4U0EgDlKz1UELxeMXLNVAj3qyhZ4U,470
74
74
  uipath/_cli/_push/sw_file_handler.py,sha256=ivHj0qzCvEP45M3x-Oi2edO5I-uhyHzgnidDF3JRoTk,36192
75
- uipath/_cli/_runtime/_contracts.py,sha256=op8dyKTayWXKsKqVqGj_vGxwthLU8nLxqIx48-ol5Kg,36216
75
+ uipath/_cli/_runtime/_contracts.py,sha256=NU7cZerrpxYTlP8-pamMBytCTMmvWy7vxPMlzFv8aBA,36231
76
76
  uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
77
77
  uipath/_cli/_runtime/_hitl.py,sha256=JAwTUKvxO4HpnZMwE4E0AegAPw_uYOwgt0OYcu6EvTg,11474
78
78
  uipath/_cli/_runtime/_logging.py,sha256=srjAi3Cy6g7b8WNHiYNjaZT4t40F3XRqquuoGd2kh4Y,14019
@@ -108,7 +108,7 @@ uipath/_resources/AGENTS.md,sha256=nRQNAVeEBaBvuMzXw8uXtMnGebLClUgwIMlgb8_qU9o,1
108
108
  uipath/_resources/CLAUDE.md,sha256=kYsckFWTVe948z_fNWLysCHvi9_YpchBXl3s1Ek03lU,10
109
109
  uipath/_resources/CLI_REFERENCE.md,sha256=M_SCtSjRhj1XwfgSFLfHJJahYXEd_CSQ_EnjLQAn-2Y,6470
110
110
  uipath/_resources/REQUIRED_STRUCTURE.md,sha256=3laqGiNa3kauJ7jRI1d7w_fWKUDkqYBjcTT_6_8FAGk,1417
111
- uipath/_resources/SDK_REFERENCE.md,sha256=0Xbt87pVXzw0ZfpPO4EnVKlwGQRoshVb8zRt8F1jAFs,18211
111
+ uipath/_resources/SDK_REFERENCE.md,sha256=xx6-FzXQpva0eeCeLgscrzaaWrVyFedxxACAD7xVlu4,18663
112
112
  uipath/_services/__init__.py,sha256=_LNy4u--VlhVtTO66bULbCoBjyJBTuyh9jnzjWrv-h4,1140
113
113
  uipath/_services/_base_service.py,sha256=x9-9jhPzn9Z16KRdFHhJNvV-FZHvTniMsDfxlS4Cutk,5782
114
114
  uipath/_services/actions_service.py,sha256=2RPMR-hFMsOlqEyjIf3aF7-lrf57jdrSD0pBjj0Kyko,16040
@@ -118,7 +118,7 @@ uipath/_services/attachments_service.py,sha256=NPQYK7CGjfBaNT_1S5vEAfODmOChTbQZf
118
118
  uipath/_services/buckets_service.py,sha256=5s8tuivd7GUZYj774DDUYTa0axxlUuesc4EBY1V5sdk,18496
119
119
  uipath/_services/connections_service.py,sha256=tKJHHOKQYKR6LkgB-V_2d0vFpLEdFeMzwj_xmBVHUDw,18416
120
120
  uipath/_services/context_grounding_service.py,sha256=Pjx-QQQEiSKD-hY6ityj3QUSALN3fIcKLLHr_NZ0d_g,37117
121
- uipath/_services/documents_service.py,sha256=dVv7kYT2wm4gbtqulSAQhtn418xgzV2yt7gB7JvDsWU,24973
121
+ uipath/_services/documents_service.py,sha256=2LZyGVYXtsC9ajsNpmLTmbgAXF13YeS4N_LObh4o4kA,31389
122
122
  uipath/_services/entities_service.py,sha256=QKCLE6wRgq3HZraF-M2mljy-8il4vsNHrQhUgkewVVk,14028
123
123
  uipath/_services/external_application_service.py,sha256=gZhnGgLn7ZYUZzZF7AumB14QEPanVY-D_02FqEcAFtw,5478
124
124
  uipath/_services/folder_service.py,sha256=9JqgjKhWD-G_KUnfUTP2BADxL6OK9QNZsBsWZHAULdE,2749
@@ -204,7 +204,7 @@ uipath/models/buckets.py,sha256=N3Lj_dVCv709-ywhOOdyCSvsuLn41eGuAfSiik6Q6F8,1285
204
204
  uipath/models/connections.py,sha256=jmzlfnddqlxjmiVhqsETRV6TQPH3fFqJGsygG0gUf7g,2745
205
205
  uipath/models/context_grounding.py,sha256=3MaF2Fv2QYle8UUWvKGkCN5XGpx2T4a34fdbBqJ2fCs,1137
206
206
  uipath/models/context_grounding_index.py,sha256=OhRyxZDHDSrEmBFK0-JLqMMMT64jir4XkHtQ54IKtc0,2683
207
- uipath/models/documents.py,sha256=g3xAhZlGcLuD6a_DHcUQWoLdzh5dENulouYAwrjGHEw,3963
207
+ uipath/models/documents.py,sha256=fLmo75okk1peDIiCmH3hmG8GbOte6fjkhwX8EaiOQJY,5124
208
208
  uipath/models/entities.py,sha256=x6jbq4o_QhgL_pCgvHFsp9O8l333kQhn8e9ZCBs72UM,9823
209
209
  uipath/models/errors.py,sha256=WCxxHBlLzLF17YxjqsFkkyBLwEQM_dc6fFU5qmBjD4A,597
210
210
  uipath/models/exceptions.py,sha256=f71VsUyonK2uuH1Cs0tpP6f9dec6v6cffL1Z9EjTxm0,1870
@@ -224,8 +224,8 @@ uipath/tracing/_utils.py,sha256=zMjiKjNpSN3YQNEU4-u5AAvPtUsi8QuEqNLya89jfAU,1446
224
224
  uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
225
225
  uipath/utils/_endpoints_manager.py,sha256=tnF_FiCx8qI2XaJDQgYkMN_gl9V0VqNR1uX7iawuLp8,8230
226
226
  uipath/utils/dynamic_schema.py,sha256=w0u_54MoeIAB-mf3GmwX1A_X8_HDrRy6p998PvX9evY,3839
227
- uipath-2.1.111.dist-info/METADATA,sha256=VJa6HaV9Xw0fWJy4saCYS5viF9gUsYDItjo_5uXmais,6626
228
- uipath-2.1.111.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
229
- uipath-2.1.111.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
230
- uipath-2.1.111.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
231
- uipath-2.1.111.dist-info/RECORD,,
227
+ uipath-2.1.112.dist-info/METADATA,sha256=n-2HKHyHbL9qb7eTshpzMv_HAh1ZDEo754AeJ6MwXag,6626
228
+ uipath-2.1.112.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
229
+ uipath-2.1.112.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
230
+ uipath-2.1.112.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
231
+ uipath-2.1.112.dist-info/RECORD,,