Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/uipath-platform/src/uipath/platform/_uipath.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .common.auth import resolve_config_from_env
from .connections import ConnectionsService
from .context_grounding import ContextGroundingService
from .document_projects import DocumentProjectsService
from .documents import DocumentsService
from .entities import EntitiesService
from .errors import BaseUrlMissingError, SecretMissingError
Expand Down Expand Up @@ -126,6 +127,10 @@ def memory(self) -> MemoryService:
def documents(self) -> DocumentsService:
return DocumentsService(self._config, self._execution_context)

@property
def document_projects(self) -> DocumentProjectsService:
return DocumentProjectsService(self._config, self._execution_context)
Comment on lines +130 to +132

@property
def queues(self) -> QueuesService:
return QueuesService(self._config, self._execution_context)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
"""UiPath IXP design-time SDK (``du_/api/designtimeapi``).

This package hosts the IXP design-time services (projects, taxonomy, labellings,
documents, models). It currently provides the shared base service;
resource services are added on top of :class:`IxpDesigntimeService`.
This package hosts the IXP design-time services (projects, and — as they land —
fields, data-types, groups, documents, labellings, models). Reach the surface via
``sdk.document_projects``; resource services build on the shared base service
:class:`IxpDesigntimeService`.
"""

from ._base_service import (
DESIGNTIME_API_BASE,
DESIGNTIME_API_VERSION,
IxpDesigntimeService,
)
from ._document_projects_service import DocumentProjectsService
from ._models import DeleteProjectResponse, Project, ProjectsPage
from ._projects_service import ProjectsService

__all__ = [
"DocumentProjectsService",
"ProjectsService",
"Project",
"ProjectsPage",
"DeleteProjectResponse",
"IxpDesigntimeService",
"DESIGNTIME_API_BASE",
"DESIGNTIME_API_VERSION",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Public facade for the IXP design-time surface (``du_/api/designtimeapi``).

:class:`DocumentProjectsService` is the entry point reached via
``sdk.document_projects``. It groups the design-time resource services under
properties named for each resource (``projects``, ``fields``, ...), so callers
write ``sdk.document_projects.projects.list()``.

Only the ``projects`` resource is wired today; sibling resources (fields,
data-types, groups, documents, labellings, deployments) are added as their
services land, each as a new property here.
"""

from functools import cached_property

from ..common._config import UiPathApiConfig
from ..common._execution_context import UiPathExecutionContext
from ._projects_service import ProjectsService


class DocumentProjectsService:
"""Grouped access to the IXP design-time resource services.

!!! warning "Preview Feature"
This service is experimental. Behavior and parameters may change in
future versions.
"""

def __init__(
self,
config: UiPathApiConfig,
execution_context: UiPathExecutionContext,
) -> None:
self._config = config
self._execution_context = execution_context

@cached_property
def projects(self) -> ProjectsService:
"""The projects resource — create, list, retrieve, update, delete."""
return ProjectsService(
config=self._config, execution_context=self._execution_context
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Pydantic models for the IXP design-time projects resource.

The design-time API serializes with PascalCase keys (``Id``, ``Name``, ...); these
models expose idiomatic snake_case attributes and map to the wire names via field
aliases, so callers work with native Python objects (``project.created_at``) rather
than the raw envelope. ``extra="allow"`` keeps forward compatibility if the API
grows fields before this SDK models them.
"""

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field


class Project(BaseModel):
"""A design-time project (``GET``/``POST``/``PATCH /api/projects``).

Mirrors the design-time API ``Project`` contract. ``name`` is the backend slug
(unique within the tenant) used to address the project in every other call;
``title`` is the human-readable display name.
"""

model_config = ConfigDict(
validate_by_name=True,
validate_by_alias=True,
extra="allow",
)

id: str = Field(alias="Id")
name: str = Field(alias="Name")
title: str = Field(alias="Title")
created_at: datetime = Field(alias="CreatedAt")


class ProjectsPage(BaseModel):
"""A page of projects (``GET /api/projects``).

``total`` is the full project count regardless of the window; ``offset`` and
``limit`` echo the applied paging window.
"""

model_config = ConfigDict(
validate_by_name=True,
validate_by_alias=True,
extra="allow",
)

projects: list[Project] = Field(alias="Projects")
total: int = Field(alias="Total")
offset: int = Field(alias="Offset")
limit: int = Field(alias="Limit")


class DeleteProjectResponse(BaseModel):
"""Result of deleting a project (``DELETE /api/projects/{projectName}``).

A minimal success confirmation; ``status`` is ``"ok"`` on success.
"""

model_config = ConfigDict(
validate_by_name=True,
validate_by_alias=True,
extra="allow",
)

status: str = Field(alias="Status")
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
"""Design-time projects resource service.

:class:`ProjectsService` covers the design-time project lifecycle — list,
retrieve, create, update (title), delete — over ``du_/api/designtimeapi``.
Sub-resources of a project (fields, data-types, taxonomy, documents, models,
...) are handled by sibling services.

It builds on :class:`IxpDesigntimeService`, so writes (create/update/delete) are
**not** retried while list/retrieve keep the platform retry policy.
"""

from uipath.core.tracing import traced

from ._base_service import IxpDesigntimeService
from ._models import DeleteProjectResponse, Project, ProjectsPage

#: Default project-list page size — matches the design-time API's server-side default.
DEFAULT_LIST_LIMIT = 50

_PROJECTS = "/api/projects"
_PROJECT = "/api/projects/{name}"


class ProjectsService(IxpDesigntimeService):
"""Manage IXP design-time projects.

Accessed as ``sdk.document_projects.projects``. Each method has an async twin
with the ``_async`` suffix.
"""

@traced(name="projects_list", run_type="uipath")
def list(self, *, offset: int = 0, limit: int = DEFAULT_LIST_LIMIT) -> ProjectsPage:
"""List projects visible to the caller.

Args:
offset: Number of projects to skip (0–1000000).
limit: Maximum number of projects to return (1–10000).

Returns:
ProjectsPage: The requested window plus the total count.
"""
response = self._get(
self._endpoint(_PROJECTS), params={"offset": offset, "limit": limit}
)
return ProjectsPage.model_validate(response.json())

@traced(name="projects_list", run_type="uipath")
async def list_async(
self, *, offset: int = 0, limit: int = DEFAULT_LIST_LIMIT
) -> ProjectsPage:
"""Asynchronously list projects visible to the caller.

Args:
offset: Number of projects to skip (0–1000000).
limit: Maximum number of projects to return (1–10000).

Returns:
ProjectsPage: The requested window plus the total count.
"""
response = await self._get_async(
self._endpoint(_PROJECTS), params={"offset": offset, "limit": limit}
)
return ProjectsPage.model_validate(response.json())

@traced(name="projects_retrieve", run_type="uipath")
def retrieve(self, project_name: str) -> Project:
"""Retrieve a project by its (slug) name.

Args:
project_name: The backend project name (slug), as returned by
:meth:`create` or :meth:`list`.

Returns:
Project: The project.
"""
response = self._get(self._endpoint(_PROJECT, name=project_name))
return Project.model_validate(response.json())

@traced(name="projects_retrieve", run_type="uipath")
async def retrieve_async(self, project_name: str) -> Project:
"""Asynchronously retrieve a project by its (slug) name.

Args:
project_name: The backend project name (slug), as returned by
:meth:`create_async` or :meth:`list_async`.

Returns:
Project: The project.
"""
response = await self._get_async(self._endpoint(_PROJECT, name=project_name))
return Project.model_validate(response.json())

@traced(name="projects_create", run_type="uipath")
def create(self, name: str) -> Project:
"""Create a project.

The API slugifies ``name`` server-side; the returned :attr:`Project.name`
is the canonical slug used to address the project in every other call.

Args:
name: Human-readable project name (1–116 characters).

Returns:
Project: The created project.
"""
response = self._post(self._endpoint(_PROJECTS), body={"Name": name})
return Project.model_validate(response.json())

@traced(name="projects_create", run_type="uipath")
async def create_async(self, name: str) -> Project:
"""Asynchronously create a project.

The API slugifies ``name`` server-side; the returned :attr:`Project.name`
is the canonical slug used to address the project in every other call.

Args:
name: Human-readable project name (1–116 characters).

Returns:
Project: The created project.
"""
response = await self._post_async(
self._endpoint(_PROJECTS), body={"Name": name}
)
return Project.model_validate(response.json())

@traced(name="projects_update", run_type="uipath")
def update(self, project_name: str, *, title: str) -> Project:
"""Update a project's display title.

``title`` is currently the only mutable field (keyword-only so the
signature can grow without breaking callers).

Args:
project_name: The backend project name (slug).
title: New display title (1–1024 characters).

Returns:
Project: The updated project.
"""
response = self._patch(
self._endpoint(_PROJECT, name=project_name), body={"Title": title}
)
return Project.model_validate(response.json())

@traced(name="projects_update", run_type="uipath")
async def update_async(self, project_name: str, *, title: str) -> Project:
"""Asynchronously update a project's display title.

``title`` is currently the only mutable field (keyword-only so the
signature can grow without breaking callers).

Args:
project_name: The backend project name (slug).
title: New display title (1–1024 characters).

Returns:
Project: The updated project.
"""
response = await self._patch_async(
self._endpoint(_PROJECT, name=project_name), body={"Title": title}
)
return Project.model_validate(response.json())

@traced(name="projects_delete", run_type="uipath")
def delete(self, project_name: str) -> DeleteProjectResponse:
"""Permanently delete a project and all its documents, taxonomy, and models.

Irreversible.

Args:
project_name: The backend project name (slug).

Returns:
DeleteProjectResponse: A success confirmation (``status == "ok"``).
"""
response = self._delete(self._endpoint(_PROJECT, name=project_name))
return DeleteProjectResponse.model_validate(response.json())

@traced(name="projects_delete", run_type="uipath")
async def delete_async(self, project_name: str) -> DeleteProjectResponse:
"""Asynchronously and permanently delete a project and all its contents.

Irreversible.

Args:
project_name: The backend project name (slug).

Returns:
DeleteProjectResponse: A success confirmation (``status == "ok"``).
"""
response = await self._delete_async(self._endpoint(_PROJECT, name=project_name))
return DeleteProjectResponse.model_validate(response.json())
Loading
Loading