@@ -647,7 +647,7 @@ def test_odata_type_already_present_not_duplicated(self):
647647 [{"@odata.type" : "Microsoft.Dynamics.CRM.account" , "name" : "Test" }],
648648 )
649649 post_calls = [c for c in self .od ._request .call_args_list if c .args [0 ] == "post" ]
650- target = post_calls [0 ].kwargs ["json" ] ["Targets" ][0 ]
650+ target = json . loads ( post_calls [0 ].kwargs ["data" ]) ["Targets" ][0 ]
651651 self .assertEqual (target ["@odata.type" ], "Microsoft.Dynamics.CRM.account" )
652652
653653 def test_body_not_dict_returns_empty_list (self ):
@@ -704,6 +704,7 @@ def setUp(self):
704704
705705 def test_cache_miss_resolves_via_entity_set_lookup (self ):
706706 """Cache miss triggers entity set lookup and populates primary ID cache."""
707+
707708 def mock_entity_set (table_schema_name ):
708709 cache_key = table_schema_name .lower ()
709710 self .od ._logical_to_entityset_cache [cache_key ] = "accounts"
@@ -716,6 +717,7 @@ def mock_entity_set(table_schema_name):
716717
717718 def test_cache_miss_no_primary_id_raises_runtime_error (self ):
718719 """Cache miss with no PrimaryIdAttribute in metadata raises RuntimeError."""
720+
719721 def mock_entity_set_no_pid (table_schema_name ):
720722 cache_key = table_schema_name .lower ()
721723 self .od ._logical_to_entityset_cache [cache_key ] = "accounts"
@@ -820,11 +822,9 @@ def test_empty_list_raises_type_error(self):
820822 def test_odata_type_already_present_not_overridden (self ):
821823 """If all records have @odata.type, it is preserved."""
822824 self .od ._request .return_value = _mock_response ()
823- records = [
824- {"@odata.type" : "Microsoft.Dynamics.CRM.CustomType" , "accountid" : "id-1" , "name" : "A" }
825- ]
825+ records = [{"@odata.type" : "Microsoft.Dynamics.CRM.CustomType" , "accountid" : "id-1" , "name" : "A" }]
826826 self .od ._update_multiple ("accounts" , "account" , records )
827- payload = self .od ._request .call_args .kwargs ["json" ]
827+ payload = json . loads ( self .od ._request .call_args .kwargs ["data" ])
828828 self .assertEqual (payload ["Targets" ][0 ]["@odata.type" ], "Microsoft.Dynamics.CRM.CustomType" )
829829
830830 def test_posts_to_update_multiple_endpoint (self ):
@@ -839,7 +839,7 @@ def test_payload_contains_targets_array(self):
839839 """_update_multiple sends {"Targets": [...]} with @odata.type injected per record."""
840840 self .od ._request .return_value = _mock_response ()
841841 self .od ._update_multiple ("accounts" , "account" , [{"accountid" : "id-1" , "name" : "X" }])
842- payload = self .od ._request .call_args .kwargs ["json" ]
842+ payload = json . loads ( self .od ._request .call_args .kwargs ["data" ])
843843 self .assertIn ("Targets" , payload )
844844 self .assertEqual (len (payload ["Targets" ]), 1 )
845845 self .assertIn ("@odata.type" , payload ["Targets" ][0 ])
@@ -866,15 +866,13 @@ def test_filters_out_falsy_ids(self):
866866
867867 def test_posts_bulk_delete_payload (self ):
868868 """_delete_multiple issues POST to BulkDelete with correct payload."""
869- self .od ._request .return_value = _mock_response (
870- json_data = {"JobId" : "job-001" }, text = '{"JobId": "job-001"}'
871- )
869+ self .od ._request .return_value = _mock_response (json_data = {"JobId" : "job-001" }, text = '{"JobId": "job-001"}' )
872870 result = self .od ._delete_multiple ("account" , ["id-1" , "id-2" ])
873871 self .assertEqual (result , "job-001" )
874872 call_args = self .od ._request .call_args
875873 self .assertEqual (call_args .args [0 ], "post" )
876874 self .assertIn ("BulkDelete" , call_args .args [1 ])
877- payload = call_args .kwargs ["json" ]
875+ payload = json . loads ( call_args .kwargs ["data" ])
878876 self .assertIn ("QuerySet" , payload )
879877 self .assertIn ("JobName" , payload )
880878 query = payload ["QuerySet" ][0 ]
@@ -1149,6 +1147,7 @@ def setUp(self):
11491147
11501148 def _setup_entity_creation (self , get_response = None ):
11511149 """Mock _request: POST returns 201, GET returns entity definition."""
1150+
11521151 def side_effect (method , url , ** kwargs ):
11531152 if method == "post" :
11541153 return _mock_response (status_code = 201 )
@@ -1324,6 +1323,7 @@ def setUp(self):
13241323
13251324 def test_empty_enum_raises_value_error (self ):
13261325 """_enum_optionset_payload raises ValueError for enum with no members."""
1326+
13271327 class EmptyEnum (Enum ):
13281328 pass
13291329
@@ -1333,6 +1333,7 @@ class EmptyEnum(Enum):
13331333
13341334 def test_int_key_in_labels_resolved_to_member_name (self ):
13351335 """__labels__ with int keys (matching enum values) are resolved to member names."""
1336+
13361337 class Status (Enum ):
13371338 Active = 1
13381339 Inactive = 2
@@ -1343,6 +1344,7 @@ class Status(Enum):
13431344
13441345 def test_enum_member_object_as_labels_key (self ):
13451346 """__labels__ with enum member objects as keys resolves member name."""
1347+
13461348 class Status (Enum ):
13471349 Active = 1
13481350 Inactive = 2
@@ -1359,6 +1361,7 @@ class Status(Enum):
13591361
13601362 def test_int_key_not_matching_any_member_raises_value_error (self ):
13611363 """__labels__ with int key not matching any member raises ValueError."""
1364+
13621365 class Status (Enum ):
13631366 Active = 1
13641367
@@ -1369,6 +1372,7 @@ class Status(Enum):
13691372
13701373 def test_duplicate_enum_values_raises_value_error (self ):
13711374 """_enum_optionset_payload raises ValueError when two members share the same int value."""
1375+
13721376 # Python treats second definition as an alias; __members__ exposes both names
13731377 class Status (Enum ):
13741378 Active = 1
@@ -1380,6 +1384,7 @@ class Status(Enum):
13801384
13811385 def test_non_int_enum_value_raises_value_error (self ):
13821386 """_enum_optionset_payload raises ValueError for enum member with a non-int value."""
1387+
13831388 class Status (Enum ):
13841389 Active = "active"
13851390
@@ -1552,7 +1557,10 @@ def test_step2_option_with_non_int_value_skipped(self):
15521557 json_data = {
15531558 "OptionSet" : {
15541559 "Options" : [
1555- {"Value" : "not-an-int" , "Label" : {"LocalizedLabels" : [{"Label" : "Active" , "LanguageCode" : 1033 }]}},
1560+ {
1561+ "Value" : "not-an-int" ,
1562+ "Label" : {"LocalizedLabels" : [{"Label" : "Active" , "LanguageCode" : 1033 }]},
1563+ },
15561564 {"Value" : 2 , "Label" : {"LocalizedLabels" : [{"Label" : "Inactive" , "LanguageCode" : 1033 }]}},
15571565 ]
15581566 }
@@ -1623,53 +1631,66 @@ def setUp(self):
16231631 self .od = _make_odata_client ()
16241632
16251633 def test_int_dtype (self ):
1634+ """'int' produces IntegerAttributeMetadata."""
16261635 result = self .od ._attribute_payload ("new_Count" , "int" )
16271636 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.IntegerAttributeMetadata" )
16281637
16291638 def test_integer_dtype_alias (self ):
1639+ """'integer' is an alias for 'int'."""
16301640 result = self .od ._attribute_payload ("new_Count" , "integer" )
16311641 self .assertIn ("Integer" , result ["@odata.type" ])
16321642
16331643 def test_decimal_dtype (self ):
1644+ """'decimal' produces DecimalAttributeMetadata."""
16341645 result = self .od ._attribute_payload ("new_Price" , "decimal" )
16351646 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.DecimalAttributeMetadata" )
16361647
16371648 def test_money_dtype_alias (self ):
1649+ """'money' is an alias for 'decimal'."""
16381650 result = self .od ._attribute_payload ("new_Revenue" , "money" )
16391651 self .assertIn ("Decimal" , result ["@odata.type" ])
16401652
16411653 def test_float_dtype (self ):
1654+ """'float' produces DoubleAttributeMetadata."""
16421655 result = self .od ._attribute_payload ("new_Score" , "float" )
16431656 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.DoubleAttributeMetadata" )
16441657
16451658 def test_double_dtype_alias (self ):
1659+ """'double' is an alias for 'float'."""
16461660 result = self .od ._attribute_payload ("new_Score" , "double" )
16471661 self .assertIn ("Double" , result ["@odata.type" ])
16481662
16491663 def test_datetime_dtype (self ):
1664+ """'datetime' produces DateTimeAttributeMetadata."""
16501665 result = self .od ._attribute_payload ("new_CreatedDate" , "datetime" )
16511666 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.DateTimeAttributeMetadata" )
16521667
16531668 def test_date_dtype_alias (self ):
1669+ """'date' is an alias for 'datetime'."""
16541670 result = self .od ._attribute_payload ("new_BirthDate" , "date" )
16551671 self .assertIn ("DateTime" , result ["@odata.type" ])
16561672
16571673 def test_bool_dtype (self ):
1674+ """'bool' produces BooleanAttributeMetadata."""
16581675 result = self .od ._attribute_payload ("new_IsActive" , "bool" )
16591676 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.BooleanAttributeMetadata" )
16601677
16611678 def test_boolean_dtype_alias (self ):
1679+ """'boolean' is an alias for 'bool'."""
16621680 result = self .od ._attribute_payload ("new_IsActive" , "boolean" )
16631681 self .assertIn ("Boolean" , result ["@odata.type" ])
16641682
16651683 def test_file_dtype (self ):
1684+ """'file' produces FileAttributeMetadata."""
16661685 result = self .od ._attribute_payload ("new_Attachment" , "file" )
16671686 self .assertEqual (result ["@odata.type" ], "Microsoft.Dynamics.CRM.FileAttributeMetadata" )
16681687
16691688 def test_unsupported_dtype_returns_none (self ):
1689+ """Unrecognized dtype string returns None."""
16701690 self .assertIsNone (self .od ._attribute_payload ("new_Unknown" , "unsupported_type" ))
16711691
16721692 def test_non_string_dtype_raises_value_error (self ):
1693+ """Non-string dtype raises ValueError."""
16731694 with self .assertRaises (ValueError ):
16741695 self .od ._attribute_payload ("new_Field" , 42 ) # type: ignore[arg-type]
16751696
@@ -1916,9 +1937,11 @@ def test_table_not_found_raises_metadata_error(self):
19161937 with self .assertRaises (MetadataError ):
19171938 self .od ._create_columns ("new_NonExistent" , {"new_Col" : "string" })
19181939
1919- def test_unsupported_column_type_raises_value_error (self ):
1920- """_create_columns raises ValueError for unsupported column type."""
1921- with self .assertRaises (ValueError ):
1940+ def test_unsupported_column_type_raises_validation_error (self ):
1941+ """Raises ValidationError for unsupported column type."""
1942+ from PowerPlatform .Dataverse .core .errors import ValidationError
1943+
1944+ with self .assertRaises (ValidationError ):
19221945 self .od ._create_columns ("new_Test" , {"new_Col" : "unsupported" })
19231946
19241947 def test_picklist_column_flushes_cache (self ):
@@ -1995,7 +2018,11 @@ def test_missing_metadata_id_raises_runtime_error(self):
19952018 def test_picklist_column_deletion_flushes_cache (self ):
19962019 """_delete_columns flushes picklist cache when a picklist column is deleted."""
19972020 self .od ._get_attribute_metadata = MagicMock (
1998- return_value = {"MetadataId" : "attr-001" , "LogicalName" : "new_status" , "@odata.type" : "PicklistAttributeMetadata" }
2021+ return_value = {
2022+ "MetadataId" : "attr-001" ,
2023+ "LogicalName" : "new_status" ,
2024+ "@odata.type" : "PicklistAttributeMetadata" ,
2025+ }
19992026 )
20002027 self .od ._flush_cache = MagicMock (return_value = 0 )
20012028 self .od ._delete_columns ("new_Test" , "new_Status" )
0 commit comments