Use CreateEntities API for table creation#183
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates table creation metadata requests to target the Dataverse CreateEntities API and adjusts supported attribute payload @odata.type values to their Complex*Metadata variants.
Changes:
- Switches
_create_entityfrom posting toEntityDefinitionsto posting toCreateEntities. - Wraps entity metadata in an
Entitieslist for the new request shape. - Updates unit expectations for complex attribute metadata and nested table payload access.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
src/PowerPlatform/Dataverse/data/_odata.py |
Updates table creation endpoint/payload and changes attribute metadata type names to Complex variants. |
tests/unit/data/test_odata_internal.py |
Updates unit test assertions for Complex metadata types and nested Entities[0] payload structure. |
Comments suppressed due to low confidence (7)
tests/unit/data/test_odata_internal.py:1529
- The test docstring still says this produces DecimalAttributeMetadata, but the expected @odata.type is now ComplexDecimalAttributeMetadata. Please update the wording to avoid documenting the old payload type.
"""'decimal' produces DecimalAttributeMetadata."""
result = self.od._attribute_payload("new_Price", "decimal")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexDecimalAttributeMetadata")
tests/unit/data/test_odata_internal.py:1539
- The test docstring still says this produces DoubleAttributeMetadata, but the expected @odata.type is now ComplexDoubleAttributeMetadata. Please update the wording to match the new payload type.
"""'float' produces DoubleAttributeMetadata."""
result = self.od._attribute_payload("new_Score", "float")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexDoubleAttributeMetadata")
tests/unit/data/test_odata_internal.py:1549
- The test docstring still says this produces DateTimeAttributeMetadata, but the expected @odata.type is now ComplexDateTimeAttributeMetadata. Please update the wording to match the new payload type.
"""'datetime' produces DateTimeAttributeMetadata."""
result = self.od._attribute_payload("new_CreatedDate", "datetime")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexDateTimeAttributeMetadata")
tests/unit/data/test_odata_internal.py:1559
- The test docstring still says this produces BooleanAttributeMetadata, but the expected @odata.type is now ComplexBooleanAttributeMetadata. Please update the wording to match the new payload type.
"""'bool' produces BooleanAttributeMetadata."""
result = self.od._attribute_payload("new_IsActive", "bool")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexBooleanAttributeMetadata")
tests/unit/data/test_odata_internal.py:1569
- The test docstring still says this produces FileAttributeMetadata, but the expected @odata.type is now ComplexFileAttributeMetadata. Please update the wording to match the new payload type.
"""'file' produces FileAttributeMetadata."""
result = self.od._attribute_payload("new_Attachment", "file")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexFileAttributeMetadata")
tests/unit/data/test_odata_internal.py:1579
- The test docstring still says this produces MemoAttributeMetadata, but the expected @odata.type is now ComplexMemoAttributeMetadata. Please update the wording to match the new payload type.
"""'memo' produces MemoAttributeMetadata with MaxLength 4000."""
result = self.od._attribute_payload("new_Notes", "memo")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexMemoAttributeMetadata")
tests/unit/data/test_odata_internal.py:1594
- The test docstring still says this produces StringAttributeMetadata, but the expected @odata.type is now ComplexStringAttributeMetadata. Please update the wording to match the new payload type.
"""'string' produces StringAttributeMetadata with MaxLength 200."""
result = self.od._attribute_payload("new_Title", "string")
self.assertEqual(result["@odata.type"], "Microsoft.Dynamics.CRM.ComplexStringAttributeMetadata")
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@microsoft-github-policy-service agree company="Microsoft" |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
src/PowerPlatform/Dataverse/data/_odata.py:2466
- This batch/deferred request builder still appends
SolutionUniqueNameas a URL query parameter even thoughCreateEntitiesis an action whose parameters belong in the JSON body. Solution-scoped table creation through batches can therefore fail or ignore the requested solution.
url = f"{self.api}/CreateEntities"
if solution:
url += f"?SolutionUniqueName={solution}"
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…b.com/microsoft/PowerPlatform-DataverseClient-Python into users/vikasrathee/create-entities-api
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>
Summary
This PR updates Dataverse table creation to use the CreateEntities API instead of posting to EntityDefinitions. It also updates the metadata payload types for supported attribute kinds to their corresponding Complex*Metadata variants so the request shape matches the new bulk/create-entities contract.
Test Executed