2525
2626import asyncio
2727import sys
28+ from enum import Enum
2829from typing import Optional , Dict , Any
2930from datetime import datetime
3031
@@ -1037,10 +1038,123 @@ async def _get_or_create(schema, columns, label):
10371038 print (f" [WARN] Could not delete { tbl } : { e } " )
10381039
10391040
1041+ async def test_picklist_table (client : AsyncDataverseClient ) -> str :
1042+ """Create a table with a local picklist column and write/read records.
1043+
1044+ Demonstrates:
1045+ - Defining a local OptionSet via an ``Enum`` subclass passed as the column ``dtype``.
1046+ - Optional multi-language labels via the ``__labels__`` class attribute.
1047+ - Writing records using either the enum member's integer value OR its label.
1048+ - Reading the integer value back, and the formatted label via
1049+ ``include_annotations="OData.Community.Display.V1.FormattedValue"``.
1050+
1051+ Returns the schema name of the table so the caller can clean it up later.
1052+ """
1053+ print ("\n -> Picklist Column Test" )
1054+ print ("=" * 50 )
1055+
1056+ table_schema_name = "test_PicklistAttribute"
1057+
1058+ # Define a local option set as an Enum. Optional __labels__ provides
1059+ # display labels per language code (1033 = English, 1036 = French).
1060+ class TaskStatus (Enum ):
1061+ NotStarted = 1
1062+ InProgress = 2
1063+ Completed = 3
1064+ Cancelled = 4
1065+
1066+ __labels__ = {
1067+ 1033 : {
1068+ "NotStarted" : "Not Started" ,
1069+ "InProgress" : "In Progress" ,
1070+ "Completed" : "Completed" ,
1071+ "Cancelled" : "Cancelled" ,
1072+ },
1073+ 1036 : {
1074+ "NotStarted" : "Non commencé" ,
1075+ "InProgress" : "En cours" ,
1076+ "Completed" : "Terminé" ,
1077+ "Cancelled" : "Annulé" ,
1078+ },
1079+ }
1080+
1081+ record_id : Optional [str ] = None
1082+ try :
1083+ # Drop any leftover table from a prior failed run so this example is idempotent.
1084+ try :
1085+ existing = await client .tables .get (table_schema_name )
1086+ if existing :
1087+ print (f" Removing leftover '{ table_schema_name } ' from a previous run..." )
1088+ await client .tables .delete (table_schema_name )
1089+ except Exception :
1090+ pass
1091+
1092+ print (f"Creating table '{ table_schema_name } ' with a picklist column 'test_status'..." )
1093+
1094+ await client .tables .create (
1095+ table_schema_name ,
1096+ primary_column = "test_name" ,
1097+ columns = {
1098+ "test_status" : TaskStatus , # Enum subclass => local picklist
1099+ "test_notes" : "string" ,
1100+ },
1101+ )
1102+
1103+ table_info = await wait_for_table_metadata (client , table_schema_name )
1104+ print (f"[OK] Picklist table ready: entity_set='{ table_info .get ('entity_set_name' )} '" )
1105+
1106+ # --- Insert one record using the enum's integer value ---
1107+ rec_by_int = {
1108+ "test_name" : f"Picklist Int { datetime .now ().strftime ('%H:%M:%S' )} " ,
1109+ "test_status" : TaskStatus .InProgress .value , # integer 2
1110+ "test_notes" : "Created using TaskStatus.InProgress.value" ,
1111+ }
1112+ record_id = await client .records .create (table_schema_name , rec_by_int )
1113+ print (f"[OK] Created record by int value: { record_id } (status={ TaskStatus .InProgress .value } )" )
1114+
1115+ # --- Insert another record using the picklist label (SDK resolves label -> int) ---
1116+ rec_by_label = {
1117+ "test_name" : f"Picklist Label { datetime .now ().strftime ('%H:%M:%S' )} " ,
1118+ "test_status" : "Completed" , # resolved via label cache to int 3
1119+ "test_notes" : "Created using label string 'Completed'" ,
1120+ }
1121+ record_id_2 = await client .records .create (table_schema_name , rec_by_label )
1122+ print (f"[OK] Created record by label: { record_id_2 } (status='Completed' -> 3)" )
1123+
1124+ # --- Read back including the FormattedValue annotation ---
1125+ annotation = "OData.Community.Display.V1.FormattedValue"
1126+ retrieved = await client .records .retrieve (
1127+ table_schema_name ,
1128+ record_id ,
1129+ select = ["test_name" , "test_status" ],
1130+ include_annotations = annotation ,
1131+ )
1132+ status_int = retrieved .get ("test_status" )
1133+ status_label = retrieved .get (f"test_status@{ annotation } " )
1134+ print (f" Retrieved: test_status={ status_int } , formatted='{ status_label } '" )
1135+ assert status_int == TaskStatus .InProgress .value , f"expected { TaskStatus .InProgress .value } , got { status_int } "
1136+
1137+ # --- List records, filtering by the picklist column ---
1138+ completed = await client .records .list (
1139+ table_schema_name ,
1140+ select = ["test_name" , "test_status" ],
1141+ filter = f"test_status eq { TaskStatus .Completed .value } " ,
1142+ include_annotations = annotation ,
1143+ )
1144+ print (f"[OK] Query by picklist value found { len (completed )} 'Completed' record(s)." )
1145+
1146+ except HttpError as e :
1147+ print (f"[ERR] HTTP error during picklist test: { e } " )
1148+ raise
1149+
1150+ return table_schema_name
1151+
1152+
10401153async def cleanup_test_data (
10411154 client : AsyncDataverseClient ,
10421155 table_info : Dict [str , Any ],
10431156 record_id : str ,
1157+ picklist_table_schema_name : Optional [str ] = None ,
10441158) -> None :
10451159 """Clean up test data."""
10461160 print ("\n -> Cleanup" )
@@ -1089,6 +1203,30 @@ async def cleanup_test_data(
10891203 else :
10901204 print ("Test table kept for future testing" )
10911205
1206+ # --- Picklist test table cleanup ---
1207+ if picklist_table_schema_name :
1208+ picklist_cleanup = (
1209+ input (f"Do you want to delete the picklist test table '{ picklist_table_schema_name } '? (y/N): " )
1210+ .strip ()
1211+ .lower ()
1212+ )
1213+ if picklist_cleanup in ["y" , "yes" ]:
1214+ for attempt in range (1 , retries + 1 ):
1215+ try :
1216+ await client .tables .delete (picklist_table_schema_name )
1217+ print (f"[OK] Picklist test table '{ picklist_table_schema_name } ' deleted successfully" )
1218+ break
1219+ except HttpError as err :
1220+ if attempt < retries :
1221+ await asyncio .sleep (delay_seconds )
1222+ continue
1223+ print (f"[WARN] Failed to delete picklist test table: { err } " )
1224+ except Exception as e :
1225+ print (f"[WARN] Failed to delete picklist test table: { e } " )
1226+ break
1227+ else :
1228+ print ("Picklist test table kept for future testing" )
1229+
10921230
10931231async def main ():
10941232 """Main async test function."""
@@ -1115,6 +1253,7 @@ async def main():
11151253 record_id = await test_create_record (client , table_info )
11161254 retrieved_record = await test_read_record (client , table_info , record_id )
11171255 await test_query_records (client , table_info )
1256+ picklist_table_info = await test_picklist_table (client )
11181257 await test_relationships (client )
11191258 await test_sql_encoding (client , table_info , retrieved_record )
11201259 await test_batch_all_operations (client , table_info )
@@ -1126,12 +1265,13 @@ async def main():
11261265 print ("[OK] Record Creation: Success" )
11271266 print ("[OK] Record Reading: Success" )
11281267 print ("[OK] Record Querying (list, list_pages, builder, fetchxml): Success" )
1268+ print ("[OK] Picklist Column: Success" )
11291269 print ("[OK] Relationship Operations: Success" )
11301270 print ("[OK] SQL Encoding: Success" )
11311271 print ("[OK] Batch Operations: Success" )
11321272 print ("\n Your async PowerPlatform Dataverse Client SDK is fully functional!" )
11331273
1134- await cleanup_test_data (client , table_info , record_id )
1274+ await cleanup_test_data (client , table_info , record_id , picklist_table_info )
11351275 finally :
11361276 await credential .close ()
11371277
0 commit comments