Skip to content

Commit 0c226bb

Browse files
author
Max Wang
committed
docstring updates
1 parent daedd9c commit 0c226bb

File tree

14 files changed

+374
-373
lines changed

14 files changed

+374
-373
lines changed

src/PowerPlatform/Dataverse/__init__.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,6 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT license.
33

4-
"""
5-
Microsoft Dataverse SDK for Python.
6-
7-
This package provides a high-level Python client for interacting with Microsoft Dataverse
8-
environments through the Web API. It supports CRUD operations, SQL queries, table metadata
9-
management, and file uploads with Azure Identity authentication.
10-
11-
Key Features:
12-
- OData CRUD operations (create, read, update, delete)
13-
- SQL query support via Web API
14-
- Table metadata operations (create, inspect, delete custom tables)
15-
- File column upload capabilities
16-
- Pandas integration for DataFrame-based operations
17-
- Azure Identity credential support
18-
19-
.. note::
20-
This SDK requires Azure Identity credentials for authentication. See the
21-
`Azure Identity documentation <https://learn.microsoft.com/python/api/overview/azure/identity-readme>`_
22-
for supported credential types.
23-
24-
Example:
25-
Basic client initialization and usage::
26-
27-
from azure.identity import InteractiveBrowserCredential
28-
from PowerPlatform.Dataverse import DataverseClient
29-
30-
credential = InteractiveBrowserCredential()
31-
client = DataverseClient(
32-
"https://org.crm.dynamics.com",
33-
credential
34-
)
35-
36-
# Create a record
37-
account_id = client.create("account", {"name": "Contoso"})[0]
38-
39-
# Query records
40-
accounts = client.get("account", filter="name eq 'Contoso'")
41-
for batch in accounts:
42-
for record in batch:
43-
print(record["name"])
44-
"""
45-
464
from .__version__ import __version__
475
from .client import DataverseClient
486

src/PowerPlatform/Dataverse/client.py

Lines changed: 50 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ class DataverseClient:
2323
Key capabilities:
2424
- OData CRUD operations: create, read, update, delete records
2525
- SQL queries: execute read-only SQL via Web API ``?sql`` parameter
26-
- Table metadata: create, inspect, and delete custom tables
26+
- Table metadata: create, inspect, and delete custom tables; create and delete columns
2727
- File uploads: upload files to file columns with chunking support
2828
2929
:param base_url: Your Dataverse environment URL, for example
3030
``"https://org.crm.dynamics.com"``. Trailing slash is automatically removed.
31-
:type base_url: str
31+
:type base_url: ``str``
3232
:param credential: Azure Identity credential for authentication.
3333
:type credential: ~azure.core.credentials.TokenCredential
3434
:param config: Optional configuration for language, timeouts, and retries.
@@ -38,8 +38,7 @@ class DataverseClient:
3838
:raises ValueError: If ``base_url`` is missing or empty after trimming.
3939
4040
.. note::
41-
The client lazily initializes its internal OData client on first use, allowing
42-
lightweight construction without immediate network calls.
41+
The client lazily initializes its internal OData client on first use, allowing lightweight construction without immediate network calls.
4342
4443
Example:
4544
Create a client and perform basic operations::
@@ -106,13 +105,13 @@ def create(self, logical_name: str, records: Union[Dict[str, Any], List[Dict[str
106105
Create one or more records by logical (singular) entity name.
107106
108107
:param logical_name: Logical (singular) entity name, e.g. ``"account"`` or ``"contact"``.
109-
:type logical_name: str
108+
:type logical_name: ``str``
110109
:param records: A single record dictionary or a list of record dictionaries.
111110
Each dictionary should contain attribute logical names as keys.
112-
:type records: dict or list[dict]
111+
:type records: ``dict`` or ``list[dict]``
113112
114113
:return: List of created record GUIDs. Returns a single-element list for a single input.
115-
:rtype: list[str]
114+
:rtype: ``list[str]``
116115
117116
:raises TypeError: If ``records`` is not a dict or list[dict], or if the internal
118117
client returns an unexpected type.
@@ -159,21 +158,19 @@ def update(self, logical_name: str, ids: Union[str, List[str]], changes: Union[D
159158
3. Paired updates: ``update("account", [id1, id2], [changes1, changes2])`` - one-to-one mapping
160159
161160
:param logical_name: Logical (singular) entity name, e.g. ``"account"``.
162-
:type logical_name: str
161+
:type logical_name: ``str``
163162
:param ids: Single GUID string or list of GUID strings to update.
164-
:type ids: str or list[str]
163+
:type ids: ``str`` or ``list[str]``
165164
:param changes: Dictionary of changes for single/broadcast mode, or list of dictionaries
166165
for paired mode. When ``ids`` is a list and ``changes`` is a single dict,
167166
the same changes are broadcast to all records. When both are lists, they must
168167
have equal length for one-to-one mapping.
169-
:type changes: dict or list[dict]
168+
:type changes: ``dict`` or ``list[dict]``
170169
171170
:raises TypeError: If ``ids`` is not str or list[str], or if ``changes`` type doesn't match usage pattern.
172171
173172
.. note::
174-
Single updates discard the response representation for better performance.
175-
For broadcast or paired updates, the method delegates to the internal client's
176-
batch update logic.
173+
Single updates discard the response representation for better performance. For broadcast or paired updates, the method delegates to the internal client's batch update logic.
177174
178175
Example:
179176
Single record update::
@@ -214,18 +211,18 @@ def delete(
214211
Delete one or more records by GUID.
215212
216213
:param logical_name: Logical (singular) entity name, e.g. ``"account"``.
217-
:type logical_name: str
214+
:type logical_name: ``str``
218215
:param ids: Single GUID string or list of GUID strings to delete.
219-
:type ids: str or list[str]
216+
:type ids: ``str`` or ``list[str]``
220217
:param use_bulk_delete: When ``True`` (default) and ``ids`` is a list, execute the BulkDelete action and
221218
return its async job identifier. When ``False`` each record is deleted sequentially.
222-
:type use_bulk_delete: bool
219+
:type use_bulk_delete: ``bool``
223220
224221
:raises TypeError: If ``ids`` is not str or list[str].
225222
:raises HttpError: If the underlying Web API delete request fails.
226223
227224
:return: BulkDelete job ID when deleting multiple records via BulkDelete; otherwise ``None``.
228-
:rtype: str or None
225+
:rtype: ``str`` or ``None``
229226
230227
Example:
231228
Delete a single record::
@@ -270,25 +267,25 @@ def get(
270267
When ``record_id`` is None, returns a generator yielding batches of records.
271268
272269
:param logical_name: Logical (singular) entity name, e.g. ``"account"``.
273-
:type logical_name: str
270+
:type logical_name: ``str``
274271
:param record_id: Optional GUID to fetch a specific record. If None, queries multiple records.
275-
:type record_id: str or None
272+
:type record_id: ``str`` or ``None``
276273
:param select: Optional list of attribute logical names to retrieve.
277-
:type select: list[str] or None
274+
:type select: ``list[str]`` or ``None``
278275
:param filter: Optional OData filter string, e.g. ``"name eq 'Contoso'"``.
279-
:type filter: str or None
276+
:type filter: ``str`` or ``None``
280277
:param orderby: Optional list of attributes to sort by, e.g. ``["name asc", "createdon desc"]``.
281-
:type orderby: list[str] or None
278+
:type orderby: ``list[str]`` or ``None``
282279
:param top: Optional maximum number of records to return.
283-
:type top: int or None
280+
:type top: ``int`` or ``None``
284281
:param expand: Optional list of navigation properties to expand.
285-
:type expand: list[str] or None
282+
:type expand: ``list[str]`` or ``None``
286283
:param page_size: Optional number of records per page for pagination.
287-
:type page_size: int or None
284+
:type page_size: ``int`` or ``None``
288285
289286
:return: Single record dict if ``record_id`` is provided, otherwise a generator
290287
yielding lists of record dictionaries (one list per page).
291-
:rtype: dict or Iterable[list[dict]]
288+
:rtype: ``dict`` or ``Iterable[list[dict]]``
292289
293290
:raises TypeError: If ``record_id`` is provided but not a string.
294291
@@ -343,18 +340,16 @@ def query_sql(self, sql: str):
343340
table alias after FROM.
344341
345342
:param sql: Supported SQL SELECT statement.
346-
:type sql: str
343+
:type sql: ``str``
347344
348345
:return: List of result row dictionaries. Returns an empty list if no rows match.
349-
:rtype: list[dict]
346+
:rtype: ``list[dict]``
350347
351348
:raises ~PowerPlatform.Dataverse.core.errors.SQLParseError: If the SQL query uses unsupported syntax.
352349
:raises ~PowerPlatform.Dataverse.core.errors.HttpError: If the Web API returns an error.
353350
354351
.. note::
355-
The SQL support is limited to read-only queries. Complex joins, subqueries,
356-
and certain SQL functions may not be supported. Consult the Dataverse
357-
documentation for the current feature set.
352+
The SQL support is limited to read-only queries. Complex joins, subqueries, and certain SQL functions may not be supported. Consult the Dataverse documentation for the current feature set.
358353
359354
Example:
360355
Basic SQL query::
@@ -378,12 +373,12 @@ def get_table_info(self, tablename: str) -> Optional[Dict[str, Any]]:
378373
379374
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
380375
(e.g. ``"new_SampleItem"``).
381-
:type tablename: str
376+
:type tablename: ``str``
382377
383378
:return: Dictionary containing table metadata with keys ``entity_schema``,
384379
``entity_logical_name``, ``entity_set_name``, and ``metadata_id``.
385380
Returns None if the table is not found.
386-
:rtype: dict or None
381+
:rtype: ``dict`` or ``None``
387382
388383
Example:
389384
Retrieve table metadata::
@@ -407,7 +402,7 @@ def create_table(
407402
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
408403
(e.g. ``"new_SampleItem"``). If a publisher prefix is not included, the default
409404
publisher prefix will be applied.
410-
:type tablename: str
405+
:type tablename: ``str``
411406
:param schema: Dictionary mapping column logical names (without prefix) to their types.
412407
Supported types:
413408
@@ -423,14 +418,14 @@ class ItemStatus(IntEnum):
423418
1036: {"Active": "Actif", "Inactive": "Inactif"}
424419
}
425420
426-
:type schema: dict[str, Any]
421+
:type schema: ``dict[str, Any]``
427422
:param solution_unique_name: Optional solution unique name that should own the new table.
428423
When omitted the table is created in the default solution.
429-
:type solution_unique_name: str or None
424+
:type solution_unique_name: ``str`` or ``None``
430425
431426
:return: Dictionary containing table metadata including ``entity_schema``,
432427
``entity_set_name``, ``entity_logical_name``, ``metadata_id``, and ``columns_created``.
433-
:rtype: dict
428+
:rtype: ``dict``
434429
435430
:raises ~PowerPlatform.Dataverse.core.errors.MetadataError: If table creation fails or the schema is invalid.
436431
@@ -467,7 +462,7 @@ def delete_table(self, tablename: str) -> None:
467462
468463
:param tablename: Table friendly name (e.g. ``"SampleItem"``) or full schema name
469464
(e.g. ``"new_SampleItem"``).
470-
:type tablename: str
465+
:type tablename: ``str``
471466
472467
:raises ~PowerPlatform.Dataverse.core.errors.MetadataError: If the table does not exist or deletion fails.
473468
@@ -487,7 +482,7 @@ def list_tables(self) -> list[str]:
487482
List all custom tables in the Dataverse environment.
488483
489484
:return: List of custom table names.
490-
:rtype: list[str]
485+
:rtype: ``list[str]``
491486
492487
Example:
493488
List all custom tables::
@@ -507,13 +502,13 @@ def create_columns(
507502
Create one or more columns on an existing table using a schema-style mapping.
508503
509504
:param tablename: Friendly name ("SampleItem") or full schema name ("new_SampleItem").
510-
:type tablename: str
505+
:type tablename: ``str``
511506
:param columns: Mapping of logical names (without prefix) to supported types. Primitive types include
512507
``string``, ``int``, ``decimal``, ``float``, ``datetime``, and ``bool``. Enum subclasses (IntEnum preferred)
513508
generate a local option set and can specify localized labels via ``__labels__``.
514-
:type columns: Dict[str, Any]
509+
:type columns: ``Dict[str, Any]``
515510
:returns: Schema names for the columns that were created.
516-
:rtype: list[str]
511+
:rtype: ``list[str]``
517512
Example:
518513
Create two columns on the custom table::
519514
@@ -540,12 +535,12 @@ def delete_columns(
540535
Delete one or more columns from a table.
541536
542537
:param tablename: Friendly or schema name of the table.
543-
:type tablename: str
538+
:type tablename: ``str``
544539
:param columns: Column name or list of column names to remove. Friendly names are normalized to schema
545540
names using the same prefix logic as ``create_columns``.
546-
:type columns: str | list[str]
541+
:type columns: ``str`` | ``list[str]``
547542
:returns: Schema names for the columns that were removed.
548-
:rtype: list[str]
543+
:rtype: ``list[str]``
549544
Example:
550545
Remove two custom columns by schema name:
551546
@@ -575,32 +570,31 @@ def upload_file(
575570
Upload a file to a Dataverse file column.
576571
577572
:param logical_name: Singular logical table name, e.g. ``"account"``.
578-
:type logical_name: str
573+
:type logical_name: ``str``
579574
:param record_id: GUID of the target record.
580-
:type record_id: str
575+
:type record_id: ``str``
581576
:param file_name_attribute: Logical name of the file column attribute.
582-
:type file_name_attribute: str
577+
:type file_name_attribute: ``str``
583578
:param path: Local filesystem path to the file. The stored filename will be
584579
the basename of this path.
585-
:type path: str
580+
:type path: ``str``
586581
:param mode: Upload strategy: ``"auto"`` (default), ``"small"``, or ``"chunk"``.
587582
Auto mode selects small or chunked upload based on file size.
588-
:type mode: str or None
583+
:type mode: ``str`` or ``None``
589584
:param mime_type: Explicit MIME type to store with the file (e.g. ``"application/pdf"``).
590585
If not provided, the MIME type may be inferred from the file extension.
591-
:type mime_type: str or None
586+
:type mime_type: ``str`` or ``None``
592587
:param if_none_match: When True (default), sends ``If-None-Match: null`` header to only
593588
succeed if the column is currently empty. Set False to always overwrite using
594589
``If-Match: *``. Used for small and chunk modes only.
595-
:type if_none_match: bool
590+
:type if_none_match: ``bool``
596591
597592
:raises ~PowerPlatform.Dataverse.core.errors.HttpError: If the upload fails or the file column is not empty
598593
when ``if_none_match=True``.
599594
:raises FileNotFoundError: If the specified file path does not exist.
600595
601596
.. note::
602-
Large files are automatically chunked to avoid request size limits. The chunk
603-
mode performs multiple requests with resumable upload support.
597+
Large files are automatically chunked to avoid request size limits. The chunk mode performs multiple requests with resumable upload support.
604598
605599
Example:
606600
Upload a PDF file::
@@ -647,10 +641,10 @@ def flush_cache(self, kind) -> int:
647641
648642
Future kinds (e.g. ``"entityset"``, ``"primaryid"``) may be added without
649643
breaking this signature.
650-
:type kind: str
644+
:type kind: ``str``
651645
652646
:return: Number of cache entries removed.
653-
:rtype: int
647+
:rtype: ``int``
654648
655649
Example:
656650
Clear the picklist cache::

src/PowerPlatform/Dataverse/core/auth.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33

44
from __future__ import annotations
55

6+
"""
7+
Authentication helpers for Dataverse.
8+
9+
This module provides :class:`~PowerPlatform.Dataverse.core.auth.AuthManager`, a thin wrapper over any Azure Identity
10+
``TokenCredential`` for acquiring OAuth2 access tokens, and :class:`~PowerPlatform.Dataverse.core.auth.TokenPair` for
11+
storing the acquired token alongside its scope.
12+
"""
13+
614
from dataclasses import dataclass
715

816
from azure.core.credentials import TokenCredential
@@ -14,9 +22,9 @@ class TokenPair:
1422
Container for an OAuth2 access token and its associated resource scope.
1523
1624
:param resource: The OAuth2 scope/resource for which the token was acquired.
17-
:type resource: str
25+
:type resource: ``str``
1826
:param access_token: The access token string.
19-
:type access_token: str
27+
:type access_token: ``str``
2028
"""
2129
resource: str
2230
access_token: str
@@ -43,7 +51,7 @@ def acquire_token(self, scope: str) -> TokenPair:
4351
Acquire an access token for the specified OAuth2 scope.
4452
4553
:param scope: OAuth2 scope string, typically ``"https://<org>.crm.dynamics.com/.default"``.
46-
:type scope: str
54+
:type scope: ``str``
4755
:return: Token pair containing the scope and access token.
4856
:rtype: ~PowerPlatform.Dataverse.core.auth.TokenPair
4957
:raises ~azure.core.exceptions.ClientAuthenticationError: If token acquisition fails.

0 commit comments

Comments
 (0)