Skip to content

Commit d0b4942

Browse files
Abel Milashclaude
andcommitted
Mirror picklist example test to async functional_testing
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>
1 parent 24f66a0 commit d0b4942

1 file changed

Lines changed: 141 additions & 1 deletion

File tree

examples/aio/basic/functional_testing.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import asyncio
2727
import sys
28+
from enum import Enum
2829
from typing import Optional, Dict, Any
2930
from 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+
10401153
async 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

10931231
async 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("\nYour 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

Comments
 (0)