From 5b9ba67737274f86f6f06f6b9129414104853bd7 Mon Sep 17 00:00:00 2001 From: Wilco Brouwer Date: Thu, 22 Oct 2026 08:35:28 +0200 Subject: [PATCH 1/2] feat(platform): list v3 entities without field definitions list_entities_v3(include_fields=False) pages through GET datafabric_/api/v3/entities/paginated, which lists the same entities as GET /v3/entities without loading their field schemas. Bumps uipath-platform to 0.2.42. Co-Authored-By: Claude Opus 5.5 --- packages/uipath-platform/pyproject.toml | 2 +- .../platform/entities/_entities_service.py | 22 ++++- .../entities/_entity_schema_service.py | 45 ++++++++++ .../tests/services/test_entities_service.py | 84 +++++++++++++++++++ packages/uipath-platform/uv.lock | 2 +- 5 files changed, 150 insertions(+), 5 deletions(-) diff --git a/packages/uipath-platform/pyproject.toml b/packages/uipath-platform/pyproject.toml index c3e51954e..512c3a940 100644 --- a/packages/uipath-platform/pyproject.toml +++ b/packages/uipath-platform/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-platform" -version = "0.2.41" +version = "0.2.42" 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/entities/_entities_service.py b/packages/uipath-platform/src/uipath/platform/entities/_entities_service.py index 7e697a55c..17c24d8be 100644 --- a/packages/uipath-platform/src/uipath/platform/entities/_entities_service.py +++ b/packages/uipath-platform/src/uipath/platform/entities/_entities_service.py @@ -323,12 +323,26 @@ def list_entities(self) -> List[Entity]: return self._schema.list_entities() @traced(name="list_entities_v3", run_type="uipath") - def list_entities_v3(self) -> List[Entity]: + def list_entities_v3(self, include_fields: bool = True) -> List[Entity]: """List all entities via the v3 API. Experimental v3 surface (serves Federated entities); see - `list_entities()` for parameter and return details. + `list_entities()` for return details. + + Args: + include_fields (bool): When `False`, list the same entities without + their field schemas, which keeps the response and the traced span + small on tenants with many entities. `Entity.fields`, + `record_count` and the storage sizes are then `None`. + + Examples: + Resolve an entity id by name:: + + entities = entities_service.list_entities_v3(include_fields=False) + ids = {entity.name: entity.id for entity in entities} """ + if not include_fields: + return self._schema.list_entities_without_fields() return self._schema.list_entities(use_v3=True) @deprecated( @@ -374,8 +388,10 @@ async def list_entities_async(self) -> List[Entity]: return await self._schema.list_entities_async() @traced(name="list_entities_v3", run_type="uipath") - async def list_entities_v3_async(self) -> List[Entity]: + async def list_entities_v3_async(self, include_fields: bool = True) -> List[Entity]: """Async variant of `list_entities_v3()`.""" + if not include_fields: + return await self._schema.list_entities_without_fields_async() return await self._schema.list_entities_async(use_v3=True) @traced(name="list_choicesets", run_type="uipath") diff --git a/packages/uipath-platform/src/uipath/platform/entities/_entity_schema_service.py b/packages/uipath-platform/src/uipath/platform/entities/_entity_schema_service.py index b49be540e..86425c328 100644 --- a/packages/uipath-platform/src/uipath/platform/entities/_entity_schema_service.py +++ b/packages/uipath-platform/src/uipath/platform/entities/_entity_schema_service.py @@ -134,6 +134,38 @@ async def list_entities_async(self, use_v3: bool = False) -> List[Entity]: entities_data = response.json() return [Entity.model_validate(entity) for entity in entities_data] + def list_entities_without_fields(self) -> List[Entity]: + """Internal implementation; see `EntitiesService.list_entities_v3()`.""" + entities: List[Entity] = [] + skip = 0 + top = 200 + + while True: + spec = self._list_entities_page_spec(skip=skip, top=top) + response = self.request(spec.method, spec.endpoint, params=spec.params) + page = response.json()["results"] + entities.extend(Entity.model_validate(entity) for entity in page) + if len(page) < top: + return entities + skip += top + + async def list_entities_without_fields_async(self) -> List[Entity]: + """Async variant of `list_entities_without_fields()`.""" + entities: List[Entity] = [] + skip = 0 + top = 200 + + while True: + spec = self._list_entities_page_spec(skip=skip, top=top) + response = await self.request_async( + spec.method, spec.endpoint, params=spec.params + ) + page = response.json()["results"] + entities.extend(Entity.model_validate(entity) for entity in page) + if len(page) < top: + return entities + skip += top + def list_choicesets(self) -> List[Entity]: """Internal implementation; see `EntitiesService.list_choicesets()`.""" spec = self._list_choicesets_spec() @@ -235,6 +267,19 @@ def _list_entities_spec(use_v3: bool = False) -> RequestSpec: endpoint=Endpoint(_schema_base(use_v3)), ) + @staticmethod + def _list_entities_page_spec(skip: int, top: int) -> RequestSpec: + """Build the GET spec for one page of entities without their fields. + + The v3 `paginated` route lists the same entities as `GET /v3/entities` + but never loads the field schemas. It accepts at most 200 per page. + """ + return RequestSpec( + method="GET", + endpoint=Endpoint(f"{_V3_ENTITIES}/paginated"), + params={"skip": skip, "top": top}, + ) + @staticmethod def _list_choicesets_spec() -> RequestSpec: """Build the GET spec for listing all choice sets.""" diff --git a/packages/uipath-platform/tests/services/test_entities_service.py b/packages/uipath-platform/tests/services/test_entities_service.py index cec8cba54..9bf7f984e 100644 --- a/packages/uipath-platform/tests/services/test_entities_service.py +++ b/packages/uipath-platform/tests/services/test_entities_service.py @@ -2724,6 +2724,90 @@ async def test_list_entities_async( entities = await service.list_entities_async() assert len(entities) == 1 + def test_list_entities_v3_includes_fields_by_default( + self, + httpx_mock: HTTPXMock, + service: EntitiesService, + base_url: str, + org: str, + tenant: str, + version: str, + ) -> None: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/datafabric_/api/v3/entities", + status_code=200, + json=[ + { + "name": "Customers", + "displayName": "Customers", + "entityType": "Entity", + "fields": [], + "isRbacEnabled": False, + "id": "ent-1", + } + ], + ) + entities = service.list_entities_v3() + assert entities[0].fields == [] + + def test_list_entities_v3_without_fields_reads_every_page( + self, + httpx_mock: HTTPXMock, + service: EntitiesService, + base_url: str, + org: str, + tenant: str, + version: str, + ) -> None: + rows = [ + { + "name": f"Entity{i}", + "displayName": f"Entity{i}", + "entityType": "Entity", + "isRbacEnabled": False, + "id": f"ent-{i}", + } + for i in range(201) + ] + for skip, page in [(0, rows[:200]), (200, rows[200:])]: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/datafabric_/api/v3/entities/paginated?skip={skip}&top=200", + status_code=200, + json={"totalCount": 201, "results": page}, + ) + entities = service.list_entities_v3(include_fields=False) + assert [e.id for e in entities] == [row["id"] for row in rows] + assert all(e.fields is None for e in entities) + + async def test_list_entities_v3_without_fields_async( + self, + httpx_mock: HTTPXMock, + service: EntitiesService, + base_url: str, + org: str, + tenant: str, + version: str, + ) -> None: + httpx_mock.add_response( + url=f"{base_url}{org}{tenant}/datafabric_/api/v3/entities/paginated?skip=0&top=200", + status_code=200, + json={ + "totalCount": 1, + "results": [ + { + "name": "Customers", + "displayName": "Customers", + "entityType": "Entity", + "isRbacEnabled": False, + "id": "ent-1", + } + ], + }, + ) + entities = await service.list_entities_v3_async(include_fields=False) + assert [e.name for e in entities] == ["Customers"] + assert entities[0].fields is None + async def test_list_records_async( self, httpx_mock: HTTPXMock, diff --git a/packages/uipath-platform/uv.lock b/packages/uipath-platform/uv.lock index 5c59bdb8e..3ef58613d 100644 --- a/packages/uipath-platform/uv.lock +++ b/packages/uipath-platform/uv.lock @@ -1095,7 +1095,7 @@ dev = [ [[package]] name = "uipath-platform" -version = "0.2.41" +version = "0.2.42" source = { editable = "." } dependencies = [ { name = "anyio" }, From fa4997d98e505a3d7f769c9077b8e9808a779629 Mon Sep 17 00:00:00 2001 From: Wilco Brouwer Date: Thu, 22 Oct 2026 08:35:29 +0200 Subject: [PATCH 2/2] chore: refresh uipath lockfile for uipath-platform 0.2.42 Co-Authored-By: Claude Opus 5.5 --- packages/uipath/uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uipath/uv.lock b/packages/uipath/uv.lock index 3e9313fca..55f3be357 100644 --- a/packages/uipath/uv.lock +++ b/packages/uipath/uv.lock @@ -2762,7 +2762,7 @@ wheels = [ [[package]] name = "uipath-platform" -version = "0.2.41" +version = "0.2.42" source = { editable = "../uipath-platform" } dependencies = [ { name = "anyio" },