You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The SDK ships a full async client, `AsyncDataverseClient`, under `PowerPlatform.Dataverse.aio`. Requires the `[async]` extra: `pip install "PowerPlatform-Dataverse-Client[async]"`.
591
591
592
+
> **Note:** snippets in this section are fragments. Every `await` line assumes it lives inside an `async def main(): ...` body with `client` and `credential` already constructed (see the Client Initialization block for the wrapper). Outside an async function, `await` is a `SyntaxError`.
593
+
592
594
### Import
593
595
```python
594
596
from azure.identity.aio import DefaultAzureCredential
@@ -597,6 +599,8 @@ from PowerPlatform.Dataverse.aio import AsyncDataverseClient
> **Complete authentication setup**: See **[Use OAuth with Dataverse](https://learn.microsoft.com/power-apps/developer/data-platform/authenticate-oauth)**for app registration, all credential types, and security configuration.
119
+
> **Set up service principal authentication**: To use `ClientSecretCredential` or `CertificateCredential` you must first register an Azure AD app and grant it access to your Dataverse environment as an application user. See **[Use OAuth with Dataverse](https://learn.microsoft.com/power-apps/developer/data-platform/authenticate-oauth)**(covers app registration, obtaining `tenant_id` / `client_id` / `client_secret`, all credential types, and security configuration).
> **Deprecation note (migration from beta):**`client.records.get()` is deprecated and emits a `DeprecationWarning`. Use `client.records.retrieve(table, record_id)` for single-record reads (returns `None` on 404 instead of raising) and `client.records.list(table, filter=...)` / `client.records.list_pages(...)` for multi-record queries. Return types differ from the beta `get()`, so the codemod flags these for manual review rather than rewriting them — run `dataverse-migrate` (see [Query data](#query-data)) to locate every call site.
> **Accessing the count:**`QueryResult` is iterable and sized — call `len(results)` to get the number of records. There is no separate `.count` or `.total_count` attribute. Because the client auto-paginates, `len(results)` reflects every matching row fetched; the server's raw `@odata.count` annotation is not surfaced as a standalone field.
493
+
466
494
**FetchXML queries** -- `client.query.fetchxml()` returns an inert `FetchXmlQuery` object; no HTTP request is made until you call `.execute()` or `.execute_pages()`:
> `continue_on_error=True` only affects how Dataverse handles per-operation
789
+
> failures on the server. Client-side errors raised before the batch is sent
790
+
> — such as `ValidationError` (e.g. exceeding the 1000-operation limit) or
791
+
> `MetadataError` from metadata pre-resolution (`tables.delete`,
792
+
> `tables.add_columns`, `tables.remove_columns`) — are still raised as
793
+
> exceptions and must be handled with `try`/`except`.
794
+
760
795
**DataFrame integration** -- feed pandas DataFrames directly into a batch:
761
796
762
797
```python
@@ -787,6 +822,8 @@ For a complete example see [examples/advanced/batch.py](https://github.com/micro
787
822
788
823
The SDK ships a full async client, `AsyncDataverseClient`, for use in async applications. It mirrors every operation of the sync client — the same namespaces (`records`, `query`, `tables`, `files`, `batch`), the same method signatures, and the same return types.
789
824
825
+
> ⓘ **Async snippets below are fragments.** Every example after `### Quick start` assumes it is nested inside an `async def main(): ...` body, with `client` and `credential` already constructed as shown in Quick start. Copying a fragment into a top-level `.py` file will raise `SyntaxError: 'await' outside function`. See [examples/aio/](https://github.com/microsoft/PowerPlatform-DataverseClient-Python/tree/main/examples/aio) for full runnable scripts.
826
+
790
827
### Install
791
828
792
829
The async client requires `aiohttp`, which is an optional extra:
@@ -908,24 +951,64 @@ For comprehensive information on Microsoft Dataverse and related technologies:
908
951
909
952
## Troubleshooting
910
953
911
-
### General
954
+
### Exception hierarchy
955
+
956
+
The SDK raises structured exceptions that all inherit from a common base, `DataverseError`. Catching the base class is the safest fallback; catch the specific subclasses when you need to react differently to validation, metadata, SQL, or HTTP failures.
957
+
958
+
```
959
+
Exception
960
+
└── DataverseError # Base class for every SDK-raised error
|**`DataverseError`**| Base class. Catch it to handle any SDK-originated failure in one block. | Fallback `except` clause. |
972
+
|**`ValidationError`**| Client-side argument validation fails **before** a request is sent. | Empty/`None` table name, missing primary key, non-string SQL, invalid batch payload, unsupported column type in `create_table`. |
973
+
|**`MetadataError`**| A metadata lookup or definition operation fails — usually an unknown or invalid table, column, or relationship. | Unknown logical name passed to `batch.create/update/delete`, `tables.create_column`, `relationships.create_*`, or `tables.delete`. |
974
+
|**`SQLParseError`**| A SQL string passed to `client.query.sql(...)` cannot be parsed into a valid SELECT. | Unsupported SQL syntax, write statements (`INSERT`/`UPDATE`/`DELETE`), malformed queries. |
975
+
|**`HttpError`**| The Dataverse Web API responded with a non-2xx status. Exposes `status_code`, `service_error_code`, `correlation_id`, `service_request_id`, `retry_after`, and `is_transient` (set for 408/429/503/504). | 401 (auth), 403 (permissions), 404 (record/table not found), 412 (concurrency/ETag), 429 (throttling), 5xx (server). |
976
+
977
+
> **Note on timeouts and network errors.** Low-level network failures from the underlying `httpx` client are **not** wrapped by the SDK and surface as their original `httpx` exceptions — most commonly `httpx.ReadTimeout`, `httpx.ConnectTimeout`, and `httpx.TimeoutException` (their common base) on slow endpoints such as `relationships.list()` or large queries, and `httpx.ConnectError`/`httpx.NetworkError` for connectivity issues. Catch `httpx.HTTPError` to cover all of them, or `httpx.TimeoutException` for timeouts specifically. The async client (`PowerPlatform.Dataverse.aio`) surfaces `aiohttp.ClientError` and `asyncio.TimeoutError` analogously.
978
+
979
+
### General
914
980
915
981
```python
982
+
import httpx
916
983
from PowerPlatform.Dataverse.client import DataverseClient
917
-
from PowerPlatform.Dataverse.core.errors import HttpError, ValidationError
0 commit comments