Skip to content

Commit cd90571

Browse files
Abel Milashclaude
andcommitted
Restore original [Unreleased] wording verbatim; add new entries grouped by PR
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 855928a commit cd90571

1 file changed

Lines changed: 25 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,45 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.0.0] - 2026-05-25
8+
## [1.0.0] - 2026-05-28
99

1010
### Added
11-
- Full async client: `AsyncDataverseClient` with complete feature parity to the sync SDK — all CRUD, query, batch, file, and DataFrame operations available as `async def`; install via `pip install PowerPlatform-Dataverse-Client[async]` and use `async with AsyncDataverseClient(...)` (#171)
12-
- `client.records.retrieve(table, record_id, *, select, expand, include_annotations)` — fetch a single record by GUID; returns `None` on 404 instead of raising (#175)
13-
- `client.records.list(table, *, filter, select, top, orderby, expand, page_size, count, include_annotations)` — eager fetch returning a flat `QueryResult`; GA replacement for `records.get()` without a record ID (#175)
14-
- `client.records.list_pages(table, *, ...)` — lazy iterator yielding one `QueryResult` per HTTP page; streaming counterpart to `list()` (#175)
15-
- `client.query.fetchxml(xml)` — FetchXML query support returning an inert `FetchXmlQuery`; no HTTP request is made until `.execute()` or `.execute_pages()` is called; implements the correct Dataverse paging cookie algorithm with a 10,000-page circuit breaker (#175)
16-
- `QueryBuilder.execute_pages()` — lazy per-page streaming; replaces `execute(by_page=True)` (#175)
17-
- `QueryBuilder.where(expr)` — composable filter expressions using `col()` and Python operators (`==`, `!=`, `>`, `>=`, `<`, `<=`, `&`, `|`, `~`); replaces the deprecated `filter_eq()`, `filter_contains()`, and other `filter_*` helpers (#175)
18-
- `QueryResult[0]` index access returns a `Record`; `QueryResult[1:5]` slice access returns a new `QueryResult` (#175)
19-
- `DataverseModel` structural `Protocol` — implement on any entity class to enable typed integration with CRUD operations without specifying table names or serializing manually (#175)
20-
- `col()`, `raw()`, `QueryResult`, and `DataverseModel` are now importable directly from `PowerPlatform.Dataverse` (#175)
21-
- Shorter import paths: `Record`, `DataverseError`, `QueryBuilder`, and other public types are now importable directly from `PowerPlatform.Dataverse.models` and `PowerPlatform.Dataverse.core` without navigating to submodule paths (#165)
22-
- v0→v1 migration tool: `dataverse-migrate` console script (also `python -m PowerPlatform.Dataverse.migration.migrate_v0_to_v1`) rewrites v0 call sites to the v1 API with `--dry-run` support; auto-rewrites `QueryBuilder.to_dataframe()` calls; marks files requiring manual attention with `[NEEDS-MANUAL]`; requires `pip install PowerPlatform-Dataverse-Client[migration]` (#175, #184)
11+
- `AsyncDataverseClient` — full async counterpart to `DataverseClient`; all operation namespaces (`records`, `query`, `tables`, `files`, `batch`, `dataframe`) exposed as `async def` methods with `async with` lifecycle management; requires `pip install PowerPlatform-Dataverse-Client[async]` (#171)
12+
- `client.records.retrieve(table, record_id, *, select, expand, include_annotations)` — fetch a single record by GUID; returns `None` on 404 instead of raising; `expand` adds `$expand` for navigation property expansion on the single-record GET; `include_annotations` maps to the `Prefer: odata.include-annotations` header for formatted values and lookup labels (#175)
13+
- `client.records.list(table, *, filter, select, top, orderby, expand, page_size, count, include_annotations)` — eager fetch returning a flat `QueryResult`; GA replacement for `records.get()` without a record ID; `page_size` controls `Prefer: odata.maxpagesize`, `count=True` adds `$count=true`, `include_annotations` requests formatted values (#175)
14+
- `client.records.list_pages(table, *, filter, select, top, orderby, expand, page_size, count, include_annotations)` — lazy iterator yielding one `QueryResult` per HTTP page; streaming counterpart to `list()`; same parameter set (#175)
15+
- `client.query.fetchxml(xml)` — FetchXML support returning an inert `FetchXmlQuery`; no HTTP request is made until `.execute()` or `.execute_pages()` is called (#175)
16+
- `FetchXmlQuery` implements the correct Dataverse paging cookie algorithm: annotation parsed as outer XML, `pagingcookie` attribute double URL-decoded, server-supplied `pagenumber` used for next page, `morerecords` handled as both `bool` and `"true"` string, `UserWarning` emitted on simple paging fallback, 32,768-character URL limit enforced (documented Dataverse GET cap), 10,000-page circuit breaker against runaway iteration (#175)
17+
- `QueryBuilder.execute_pages()` — lazy per-page streaming returning one `QueryResult` per HTTP page; replaces deprecated `execute(by_page=True)` (#175)
18+
- `QueryBuilder.where()` — composable filter expressions using `col()` and Python operators (`==`, `>`, `&`, `|`, `~`); replaces deprecated `filter_eq()`, `filter_contains()`, and other `filter_*` helpers (#175)
19+
- `QueryResult.__getitem__` — index access (`result[0]`) returns a `Record`; slice access (`result[1:5]`) returns a new `QueryResult` (#175)
20+
- `DataverseModel` structural `Protocol` (`models/protocol.py`) — implement on any entity class to enable typed integration with CRUD operations without specifying table names or serializing manually (#175)
21+
- `col()`, `raw()`, `QueryResult`, and `DataverseModel` exported from the top-level `PowerPlatform.Dataverse` package (#175)
22+
- v0→v1 migration tool: installed as the `dataverse-migrate` console script (also runnable via `python -m PowerPlatform.Dataverse.migration.migrate_v0_to_v1`); rewrites v0 call sites to the v1 API with `--dry-run` support; covers `create`, `update`, `delete`, `get`, `list`, `fetchxml`, and query builder patterns; requires the `[migration]` optional extra (`pip install PowerPlatform-Dataverse-Client[migration]`) (#175)
23+
- Migration tool now auto-rewrites `QueryBuilder.to_dataframe()``.execute().to_dataframe()` (inserts `.execute()` when receiver is a recognised builder chain); output improved with `[NEEDS-MANUAL]` label for files that have no auto-rewrites but require manual attention, and a trailing note on `[MIGRATED]` lines when manual items remain (#175)
24+
- Public types (`Record`, `DataverseError`, `QueryBuilder`, `BatchResult`, and others) are now importable directly from `PowerPlatform.Dataverse.models`, `PowerPlatform.Dataverse.core`, and `PowerPlatform.Dataverse.operations` without navigating into submodule paths (#165)
2325

2426
### Changed
2527
- `QueryBuilder.execute()` now returns a flat `QueryResult` (all pages collected eagerly) instead of `Iterable[Record]` (#175)
26-
- `records.get()` deprecation extended: calling with a `record_id` directs to `retrieve()`; calling without one directs to `list()` (#175)
28+
- `records.get()` deprecation extended: calling with a `record_id` emits `DeprecationWarning` directing callers to `retrieve()`; calling without a `record_id` directs callers to `list()` (#175)
29+
- `OperationContext` now validates keys against an allowlist (`app`, `skill`, `agent`) and values against per-key format rules; unknown keys or non-conforming values raise `ValidationError` at construction time, preventing PII from reaching the `User-Agent` header (#181)
30+
- `client.tables.create()` now uses the `CreateEntities` API instead of `EntityDefinitions`, improving reliability and aligning with the current Dataverse API contract (#183)
2731
- `float` and `double` column precision default raised from 2 to 5 decimal places, preventing silent truncation of values like `2.718` (#185)
28-
- Server-side error detail (`error.innererror.message`) is now included in `HttpError.message` and batch failure details, making the offending field or data type visible without inspecting raw wire payloads (#185)
29-
- `OperationContext` now validates keys and values against a fixed allowlist (`app`, `skill`, `agent`); unknown keys or non-conforming values raise `ValidationError` at construction time, preventing PII from reaching the `User-Agent` header (#181)
30-
- Table creation now uses the `CreateEntities` API, improving reliability and aligning with the current Dataverse API contract (#183)
31-
- `pandas.DataFrame` with MultiIndex columns now raises a descriptive error with a flatten hint at the point of use, instead of producing broken tuple keys deep in the serialization path (#185)
32+
- Server-side error detail (`error.innererror.message`) is now appended to `HttpError.message` on both single-request and batch paths, surfacing the offending field or data type without inspecting raw wire payloads (#185)
33+
- `pandas.DataFrame` with MultiIndex columns now raises a clear error with a flatten hint at the point of use, instead of producing broken tuple keys deep in the serialization path (#185)
3234

3335
### Deprecated
3436
- `QueryBuilder.execute(by_page=True)` and `execute(by_page=False)` emit `UserWarning`; use `execute_pages()` and `execute()` respectively (#175)
35-
- `client.query.odata_select()`, `odata_expands()`, `odata_expand()`, `odata_bind()` emit `DeprecationWarning`; use `QueryBuilder.expand()` instead (#175)
37+
- `client.query.odata_select()`, `client.query.odata_expands()`, `client.query.odata_expand()`, `client.query.odata_bind()` emit `DeprecationWarning`; navigation property helpers are replaced by `QueryBuilder.expand()` (#175)
3638

3739
### Removed
38-
- All v0 flat methods on `DataverseClient` (`create`, `update`, `delete`, `get`, `list`, `query_sql`, etc.); use the `client.records`, `client.query`, and `client.batch` namespaces (#175)
39-
- `client.query.sql_select()`, `sql_joins()`, `sql_join()` (#175)
40+
- All v0 flat methods on `DataverseClient` (`create`, `update`, `delete`, `get`, `list`, `query_sql`, etc.) removed (~570 lines); use the `client.records`, `client.query`, and `client.batch` namespaces (#175)
41+
- `client.query.sql_select()`, `client.query.sql_joins()`, `client.query.sql_join()` removed (#175)
4042

4143
### Fixed
42-
- `async for record in results:` now works correctly; `QueryResult` was missing `__aiter__`, causing `async for` to fail in async code (#187)
43-
- Client creation raised an error on Python 3.10 and 3.11; all supported Python versions (3.10–3.14) now work correctly (#188)
4444
- SQL guardrails now block write statements and statement stacking even when hidden inside comments, string literals, or zero-width prefixes (#185)
45+
- `records.get()` deprecation warning now names both migration paths: `retrieve()` for single-by-ID lookups and `list(filter=...)` for filtered queries (#185)
46+
- Fixed client creation error on Python 3.10 and 3.11; all supported Python versions (3.10–3.14) now work correctly (#188)
4547

4648
## [0.1.0b10] - 2026-05-12
4749

0 commit comments

Comments
 (0)