Skip to content

Commit c248495

Browse files
tpellissierclaude
andcommitted
Address PR review feedback
- Move OData type constants to common/constants.py - Add input/output examples to metadata to_dict() docstrings - Remove .NET SDK references from _relationships.py docstrings - Add __all__ to models/__init__.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 073e369 commit c248495

5 files changed

Lines changed: 164 additions & 16 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
"""
5+
Common utilities and constants for the Dataverse SDK.
6+
7+
This module contains shared constants and utilities used across the SDK.
8+
"""
9+
10+
__all__ = []
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
"""
5+
Constants for Dataverse Web API metadata types.
6+
7+
These constants define the OData type identifiers used in Web API payloads
8+
for metadata operations.
9+
"""
10+
11+
# OData type identifiers for metadata entities
12+
ODATA_TYPE_LOCALIZED_LABEL = "Microsoft.Dynamics.CRM.LocalizedLabel"
13+
ODATA_TYPE_LABEL = "Microsoft.Dynamics.CRM.Label"
14+
ODATA_TYPE_LOOKUP_ATTRIBUTE = "Microsoft.Dynamics.CRM.LookupAttributeMetadata"
15+
ODATA_TYPE_ONE_TO_MANY_RELATIONSHIP = "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata"
16+
ODATA_TYPE_MANY_TO_MANY_RELATIONSHIP = "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata"
17+
18+
19+
__all__ = [
20+
"ODATA_TYPE_LOCALIZED_LABEL",
21+
"ODATA_TYPE_LABEL",
22+
"ODATA_TYPE_LOOKUP_ATTRIBUTE",
23+
"ODATA_TYPE_ONE_TO_MANY_RELATIONSHIP",
24+
"ODATA_TYPE_MANY_TO_MANY_RELATIONSHIP",
25+
]

src/PowerPlatform/Dataverse/data/_relationships.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ def _create_one_to_many_relationship(
3232
"""
3333
Create a one-to-many relationship with lookup attribute.
3434
35-
This mirrors the CreateOneToManyRequest from the .NET SDK by posting
36-
to /RelationshipDefinitions with OneToManyRelationshipMetadata.
35+
Posts to /RelationshipDefinitions with OneToManyRelationshipMetadata.
3736
3837
:param lookup: Lookup attribute metadata (LookupAttributeMetadata instance).
3938
:type lookup: ~PowerPlatform.Dataverse.models.metadata.LookupAttributeMetadata
@@ -78,8 +77,7 @@ def _create_many_to_many_relationship(
7877
"""
7978
Create a many-to-many relationship.
8079
81-
This mirrors the CreateManyToManyRequest from the .NET SDK by posting
82-
to /RelationshipDefinitions with ManyToManyRelationshipMetadata.
80+
Posts to /RelationshipDefinitions with ManyToManyRelationshipMetadata.
8381
8482
:param relationship: Relationship metadata (ManyToManyRelationshipMetadata instance).
8583
:type relationship: ~PowerPlatform.Dataverse.models.metadata.ManyToManyRelationshipMetadata

src/PowerPlatform/Dataverse/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
# Licensed under the MIT license.
33

44
"""Data models for Dataverse metadata types."""
5+
6+
__all__ = []

src/PowerPlatform/Dataverse/models/metadata.py

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
from typing import Any, Dict, List, Optional
1616
from dataclasses import dataclass, field
1717

18+
from ..common.constants import (
19+
ODATA_TYPE_LOCALIZED_LABEL,
20+
ODATA_TYPE_LABEL,
21+
ODATA_TYPE_LOOKUP_ATTRIBUTE,
22+
ODATA_TYPE_ONE_TO_MANY_RELATIONSHIP,
23+
ODATA_TYPE_MANY_TO_MANY_RELATIONSHIP,
24+
)
25+
1826

1927
@dataclass
2028
class LocalizedLabel:
@@ -35,9 +43,21 @@ class LocalizedLabel:
3543
additional_properties: Optional[Dict[str, Any]] = None
3644

3745
def to_dict(self) -> Dict[str, Any]:
38-
"""Convert to Web API JSON format."""
46+
"""
47+
Convert to Web API JSON format.
48+
49+
Example::
50+
51+
>>> label = LocalizedLabel(label="Account", language_code=1033)
52+
>>> label.to_dict()
53+
{
54+
'@odata.type': 'Microsoft.Dynamics.CRM.LocalizedLabel',
55+
'Label': 'Account',
56+
'LanguageCode': 1033
57+
}
58+
"""
3959
result = {
40-
"@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
60+
"@odata.type": ODATA_TYPE_LOCALIZED_LABEL,
4161
"Label": self.label,
4262
"LanguageCode": self.language_code,
4363
}
@@ -65,9 +85,23 @@ class Label:
6585
additional_properties: Optional[Dict[str, Any]] = None
6686

6787
def to_dict(self) -> Dict[str, Any]:
68-
"""Convert to Web API JSON format."""
88+
"""
89+
Convert to Web API JSON format.
90+
91+
Example::
92+
93+
>>> label = Label(localized_labels=[LocalizedLabel("Account", 1033)])
94+
>>> label.to_dict()
95+
{
96+
'@odata.type': 'Microsoft.Dynamics.CRM.Label',
97+
'LocalizedLabels': [
98+
{'@odata.type': '...', 'Label': 'Account', 'LanguageCode': 1033}
99+
],
100+
'UserLocalizedLabel': {'@odata.type': '...', 'Label': 'Account', ...}
101+
}
102+
"""
69103
result = {
70-
"@odata.type": "Microsoft.Dynamics.CRM.Label",
104+
"@odata.type": ODATA_TYPE_LABEL,
71105
"LocalizedLabels": [ll.to_dict() for ll in self.localized_labels],
72106
}
73107
# Use explicit user_localized_label, or default to first localized label
@@ -118,7 +152,22 @@ class CascadeConfiguration:
118152
additional_properties: Optional[Dict[str, Any]] = None
119153

120154
def to_dict(self) -> Dict[str, Any]:
121-
"""Convert to Web API JSON format."""
155+
"""
156+
Convert to Web API JSON format.
157+
158+
Example::
159+
160+
>>> config = CascadeConfiguration(delete="Cascade", assign="NoCascade")
161+
>>> config.to_dict()
162+
{
163+
'Assign': 'NoCascade',
164+
'Delete': 'Cascade',
165+
'Merge': 'NoCascade',
166+
'Reparent': 'NoCascade',
167+
'Share': 'NoCascade',
168+
'Unshare': 'NoCascade'
169+
}
170+
"""
122171
result = {
123172
"Assign": self.assign,
124173
"Delete": self.delete,
@@ -163,7 +212,15 @@ class AssociatedMenuConfiguration:
163212
additional_properties: Optional[Dict[str, Any]] = None
164213

165214
def to_dict(self) -> Dict[str, Any]:
166-
"""Convert to Web API JSON format."""
215+
"""
216+
Convert to Web API JSON format.
217+
218+
Example::
219+
220+
>>> menu = AssociatedMenuConfiguration(behavior="UseLabel", group="Details")
221+
>>> menu.to_dict()
222+
{'Behavior': 'UseLabel', 'Group': 'Details', 'Order': 10000}
223+
"""
167224
result = {
168225
"Behavior": self.behavior,
169226
"Group": self.group,
@@ -209,9 +266,27 @@ class LookupAttributeMetadata:
209266
additional_properties: Optional[Dict[str, Any]] = None
210267

211268
def to_dict(self) -> Dict[str, Any]:
212-
"""Convert to Web API JSON format."""
269+
"""
270+
Convert to Web API JSON format.
271+
272+
Example::
273+
274+
>>> lookup = LookupAttributeMetadata(
275+
... schema_name="new_AccountId",
276+
... display_name=Label([LocalizedLabel("Account", 1033)])
277+
... )
278+
>>> lookup.to_dict()
279+
{
280+
'@odata.type': 'Microsoft.Dynamics.CRM.LookupAttributeMetadata',
281+
'SchemaName': 'new_AccountId',
282+
'AttributeType': 'Lookup',
283+
'AttributeTypeName': {'Value': 'LookupType'},
284+
'DisplayName': {...},
285+
'RequiredLevel': {'Value': 'None', 'CanBeChanged': True, ...}
286+
}
287+
"""
213288
result = {
214-
"@odata.type": "Microsoft.Dynamics.CRM.LookupAttributeMetadata",
289+
"@odata.type": ODATA_TYPE_LOOKUP_ATTRIBUTE,
215290
"SchemaName": self.schema_name,
216291
"AttributeType": "Lookup",
217292
"AttributeTypeName": {"Value": "LookupType"},
@@ -265,9 +340,29 @@ class OneToManyRelationshipMetadata:
265340
additional_properties: Optional[Dict[str, Any]] = None
266341

267342
def to_dict(self) -> Dict[str, Any]:
268-
"""Convert to Web API JSON format."""
343+
"""
344+
Convert to Web API JSON format.
345+
346+
Example::
347+
348+
>>> rel = OneToManyRelationshipMetadata(
349+
... schema_name="new_account_orders",
350+
... referenced_entity="account",
351+
... referencing_entity="new_order",
352+
... referenced_attribute="accountid"
353+
... )
354+
>>> rel.to_dict()
355+
{
356+
'@odata.type': 'Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata',
357+
'SchemaName': 'new_account_orders',
358+
'ReferencedEntity': 'account',
359+
'ReferencingEntity': 'new_order',
360+
'ReferencedAttribute': 'accountid',
361+
'CascadeConfiguration': {...}
362+
}
363+
"""
269364
result = {
270-
"@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
365+
"@odata.type": ODATA_TYPE_ONE_TO_MANY_RELATIONSHIP,
271366
"SchemaName": self.schema_name,
272367
"ReferencedEntity": self.referenced_entity,
273368
"ReferencingEntity": self.referencing_entity,
@@ -317,11 +412,29 @@ class ManyToManyRelationshipMetadata:
317412
additional_properties: Optional[Dict[str, Any]] = None
318413

319414
def to_dict(self) -> Dict[str, Any]:
320-
"""Convert to Web API JSON format."""
415+
"""
416+
Convert to Web API JSON format.
417+
418+
Example::
419+
420+
>>> rel = ManyToManyRelationshipMetadata(
421+
... schema_name="new_account_contact",
422+
... entity1_logical_name="account",
423+
... entity2_logical_name="contact"
424+
... )
425+
>>> rel.to_dict()
426+
{
427+
'@odata.type': 'Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata',
428+
'SchemaName': 'new_account_contact',
429+
'Entity1LogicalName': 'account',
430+
'Entity2LogicalName': 'contact',
431+
'IntersectEntityName': 'new_account_contact'
432+
}
433+
"""
321434
# IntersectEntityName is required - use provided value or default to schema_name
322435
intersect_name = self.intersect_entity_name or self.schema_name
323436
result = {
324-
"@odata.type": "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata",
437+
"@odata.type": ODATA_TYPE_MANY_TO_MANY_RELATIONSHIP,
325438
"SchemaName": self.schema_name,
326439
"Entity1LogicalName": self.entity1_logical_name,
327440
"Entity2LogicalName": self.entity2_logical_name,

0 commit comments

Comments
 (0)