Add async support for Dataverse SDK#171
Open
abelmilash-msft wants to merge 36 commits into
Open
Conversation
e491241 to
b848324
Compare
b32987a to
ad9297e
Compare
f52d6b8 to
8ff97e4
Compare
8ff97e4 to
a23cecd
Compare
a23cecd to
4a319bf
Compare
4a319bf to
68e705a
Compare
500c19f to
55e3359
Compare
a374227 to
602c990
Compare
- Reset to main (which is now PR #175) - Re-apply: _ODataBase, _BatchBase, _QueryBuilderBase, _BatchContext Protocol, _operation_context in base, Self type annotation - Re-export multipart helpers from _batch.py for test compatibility - Update test_sql_parse.py patch target to _odata_base.urlparse Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Reset to main via refactoring branch - Restore full async implementation: aio/ client, HTTP, batch, OData, relationships, upload, query builder, fetchxml, operations, tests, examples - Re-export multipart helpers from _batch.py for test compatibility - All 2166 tests passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
602c990 to
a4f69cd
Compare
…ession on auth failure - functional_testing.py: replace batch.records.get() with batch.records.retrieve(); close client session on auth failure to avoid unclosed session warning - sql_examples.py: remove odata_select/odata_expand/odata_bind calls (deprecated sync-only helpers not available on async client); keep only odata_expands() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ontent _AsyncResponse buffers the body in ._body; it has no .content attribute (unlike requests.Response used by the sync client). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…replace downloads Two download paths after replace uploads still used resp_r.content and resp_rc.content instead of ._body, causing AttributeError. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validates 7 properties of the async client against a live environment: 1. Non-blocking reads — canary confirms event loop stays free during GETs 2. Read throughput — concurrent reads via gather() beat sequential 3. Write concurrency — concurrent POSTs beat sequential (POST path) 4. Pagination non-blocking — async generators yield between page fetches 5. Mixed fan-out — different op types run simultaneously without serialization 6. Error resilience — one failure in gather() does not kill other calls 7. Real-world fan-out — metadata for multiple tables fetched in parallel Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each test now has a brief explanation of what it runs, what property it validates, and what a failure would indicate. Also clarifies that speedup measures async-sequential vs async-concurrent, not async vs sync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Populate __all__ in aio, aio.models, and aio.operations __init__.py files so public symbols are importable directly from the package namespace. Update all async examples, README, and skill docs to use the shorter import paths. Add test_async_package_exports.py mirroring the sync test_package_exports.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'dv' is not in _ALLOWED_SKILLS (added to config.py on main). The PR build tests the merged result so it picked up the validation. Update to use 'dv-data' which is an allowed value. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sync side was updated to use the new CreateEntities API in PR #183. The async client has its own copy of _create_entity and _create_table, so we need to mirror those changes manually: - _AsyncODataClient._create_entity(): URL EntityDefinitions -> CreateEntities, payload wrapped in Entities[0] array with @odata.type ComplexEntityMetadata - _AsyncODataClient._create_table(): pass complex=True to _attribute_payload calls so attribute metadata uses the Complex*Metadata variants required by CreateEntities The shared base (_odata_base.py) changes from PR #183 — including the _attribute_payload(complex=...) parameter and Complex*Metadata output — flow into the async client automatically via inheritance. Also picks up PR #181 (OperationContext key/value allowlisting) via the same main merge. Tests: 2187 pass, black clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts commit c1f1237.
Sync side was updated to use the new CreateEntities API in PR #183. The async client has its own copy of _create_entity and _create_table, so we need to mirror those changes manually: - _AsyncODataClient._create_entity(): URL EntityDefinitions -> CreateEntities, payload wrapped in Entities[0] array with @odata.type ComplexEntityMetadata - _AsyncODataClient._create_table(): pass complex=True to _attribute_payload calls so attribute metadata uses the Complex*Metadata variants required by CreateEntities The shared base (_odata_base.py) changes from PR #183 -- including the _attribute_payload(complex=...) parameter and Complex*Metadata output -- flow into the async client automatically via inheritance. This is a clean re-apply of the legitimate diff after reverting commit c1f1237, which accidentally committed many untracked scratch/build files alongside this change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The sync side added test_url_targets_create_entities and updated several _create_table assertions to use Entities[0] in PR #183. Those tests only cover the sync _create_entity; the async client has its own copy. Add three tests to cover the async-side behavior: - test_create_entity_url_targets_create_entities: URL ends with /CreateEntities - test_create_entity_payload_wraps_in_entities_array: body has Entities[0] with @odata.type=ComplexEntityMetadata - test_create_table_posts_complex_attribute_metadata: _create_table forwards complex=True so the posted Attributes use Complex*AttributeMetadata variants Tests: 2190 pass (up from 2187), _async_odata.py coverage at 98%. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PR #183 added a test_picklist_table scenario to the sync functional testing script demonstrating local OptionSet creation via an Enum subclass, label-cache resolution on write, and FormattedValue annotation on read. Mirror the same flow to examples/aio/basic/functional_testing.py so async users have parity coverage: - New async test_picklist_table() using await client.tables.create(), client.records.create(), client.records.retrieve(), client.records.list() - cleanup_test_data() takes an optional picklist_table_schema_name and prompts for the picklist table teardown - Wire test_picklist_table into main() with corresponding summary line Unit tests: 2190 pass (unchanged; this is an example-only script). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Warning
ADO PR pipeline YAML change detected
This PR modifies .azdo/ci-pr.yaml. After merge, Azure DevOps may disable or require approval for the PR validation pipeline.
Action required (post-merge): Re-enable / approve the updated YAML for:
- DV-Python-SDK-PullRequest (definitionId=29922)
- https://dev.azure.com/dynamicscrm/OneCRM/_build?definitionId=29922
Please resolve this comment after completing the post-merge steps.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
aio/async package mirroring the sync SDK:_AsyncHttpClientwrappingaiohttpwith identical retry, backoff, and timeout logic_AsyncAuthManagerfor async Azure Identity token acquisition_AsyncODataClient— full CRUD, SQL-over-API, table/column metadata, file upload, and relationship operations_AsyncBatchClientwith_SyncResponseWrapperbridging the async HTTP response to the shared sync multipart parser in_BatchBaserecords,tables,query,files,batch,dataframe— all mirroring their sync counterpartsAsyncDataverseClientwith lazy init, async context manager, and session lifecycle managementpytest-asyncio(asyncio_mode = auto) andaiohttpas an optional dependency (pip install PowerPlatform-Dataverse-Client[async]).Test plan
black --checkpasses on all files