Skip to content

Commit e52b5dd

Browse files
committed
add picklist attribute type table creation in functional tests
1 parent 389a47f commit e52b5dd

1 file changed

Lines changed: 164 additions & 2 deletions

File tree

examples/basic/functional_testing.py

Lines changed: 164 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import sys
2929
import time
30+
from enum import Enum
3031
from typing import Optional, Dict, Any
3132
from datetime import datetime
3233

@@ -909,7 +910,12 @@ def test_batch_all_operations(client: DataverseClient, table_info: Dict[str, Any
909910
pass
910911

911912

912-
def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], record_id: str) -> None:
913+
def cleanup_test_data(
914+
client: DataverseClient,
915+
table_info: Dict[str, Any],
916+
record_id: str,
917+
picklist_table_schema_name: Optional[str] = None,
918+
) -> None:
913919
"""Clean up test data."""
914920
print("\n-> Cleanup")
915921
print("=" * 50)
@@ -979,6 +985,46 @@ def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], recor
979985
else:
980986
print("Test table kept for future testing")
981987

988+
# --- Picklist test table cleanup ---
989+
if picklist_table_schema_name:
990+
picklist_cleanup = (
991+
input(f"Do you want to delete the picklist test table '{picklist_table_schema_name}'? (y/N): ")
992+
.strip()
993+
.lower()
994+
)
995+
if picklist_cleanup in ["y", "yes"]:
996+
for attempt in range(1, retries + 1):
997+
try:
998+
client.tables.delete(picklist_table_schema_name)
999+
print(f"[OK] Picklist test table '{picklist_table_schema_name}' deleted successfully")
1000+
break
1001+
except HttpError as err:
1002+
status = getattr(err, "status_code", None)
1003+
if status == 404:
1004+
if _table_still_exists(client, picklist_table_schema_name):
1005+
if attempt < retries:
1006+
print(
1007+
f" Picklist table delete retry {attempt}/{retries} after metadata 404 ({err}). Waiting {delay_seconds}s..."
1008+
)
1009+
time.sleep(delay_seconds)
1010+
continue
1011+
print(f"[WARN] Failed to delete picklist test table due to metadata delay: {err}")
1012+
break
1013+
print("[OK] Picklist test table deleted successfully (404 reported).")
1014+
break
1015+
if attempt < retries:
1016+
print(
1017+
f" Picklist table delete retry {attempt}/{retries} after error ({err}). Waiting {delay_seconds}s..."
1018+
)
1019+
time.sleep(delay_seconds)
1020+
continue
1021+
print(f"[WARN] Failed to delete picklist test table: {err}")
1022+
except Exception as e:
1023+
print(f"[WARN] Failed to delete picklist test table: {e}")
1024+
break
1025+
else:
1026+
print("Picklist test table kept for future testing")
1027+
9821028

9831029
def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)):
9841030
"""Retry helper with exponential backoff for metadata propagation delays."""
@@ -1260,6 +1306,118 @@ def _get_or_create(schema, columns, label):
12601306
print(f" [WARN] Could not delete {tbl}: {e}")
12611307

12621308

1309+
def test_picklist_table(client: DataverseClient) -> str:
1310+
"""Create a table with a local picklist column and write/read records.
1311+
1312+
Demonstrates:
1313+
- Defining a local OptionSet via an ``Enum`` subclass passed as the column ``dtype``.
1314+
- Optional multi-language labels via the ``__labels__`` class attribute.
1315+
- Writing records using either the enum member's integer value OR its label.
1316+
- Reading the integer value back, and the formatted label via
1317+
``include_annotations="OData.Community.Display.V1.FormattedValue"``.
1318+
1319+
Returns the schema name of the table so the caller can clean it up later.
1320+
"""
1321+
print("\n-> Picklist Column Test")
1322+
print("=" * 50)
1323+
1324+
table_schema_name = "test_PicklistAttribute"
1325+
1326+
# Define a local option set as an Enum. Optional __labels__ provides
1327+
# display labels per language code (1033 = English, 1036 = French).
1328+
class TaskStatus(Enum):
1329+
NotStarted = 1
1330+
InProgress = 2
1331+
Completed = 3
1332+
Cancelled = 4
1333+
1334+
__labels__ = {
1335+
1033: {
1336+
"NotStarted": "Not Started",
1337+
"InProgress": "In Progress",
1338+
"Completed": "Completed",
1339+
"Cancelled": "Cancelled",
1340+
},
1341+
1036: {
1342+
"NotStarted": "Non commencé",
1343+
"InProgress": "En cours",
1344+
"Completed": "Terminé",
1345+
"Cancelled": "Annulé",
1346+
},
1347+
}
1348+
1349+
record_id: Optional[str] = None
1350+
try:
1351+
# Drop any leftover table from a prior failed run so this example is idempotent.
1352+
try:
1353+
existing = client.tables.get(table_schema_name)
1354+
if existing:
1355+
print(f" Removing leftover '{table_schema_name}' from a previous run...")
1356+
client.tables.delete(table_schema_name)
1357+
except Exception:
1358+
pass
1359+
1360+
print(f"Creating table '{table_schema_name}' with a picklist column 'test_status'...")
1361+
1362+
client.tables.create(
1363+
table_schema_name,
1364+
primary_column="test_name",
1365+
columns={
1366+
"test_status": TaskStatus, # Enum subclass => local picklist
1367+
"test_notes": "string",
1368+
},
1369+
)
1370+
1371+
table_info = wait_for_table_metadata(client, table_schema_name)
1372+
print(f"[OK] Picklist table ready: entity_set='{table_info.get('entity_set_name')}'")
1373+
1374+
# --- Insert one record using the enum's integer value ---
1375+
rec_by_int = {
1376+
"test_name": f"Picklist Int {datetime.now().strftime('%H:%M:%S')}",
1377+
"test_status": TaskStatus.InProgress.value, # integer 2
1378+
"test_notes": "Created using TaskStatus.InProgress.value",
1379+
}
1380+
record_id = client.records.create(table_schema_name, rec_by_int)
1381+
print(f"[OK] Created record by int value: {record_id} (status={TaskStatus.InProgress.value})")
1382+
1383+
# --- Insert another record using the picklist label (SDK resolves label -> int) ---
1384+
rec_by_label = {
1385+
"test_name": f"Picklist Label {datetime.now().strftime('%H:%M:%S')}",
1386+
"test_status": "Completed", # resolved via label cache to int 3
1387+
"test_notes": "Created using label string 'Completed'",
1388+
}
1389+
record_id_2 = client.records.create(table_schema_name, rec_by_label)
1390+
print(f"[OK] Created record by label: {record_id_2} (status='Completed' -> 3)")
1391+
1392+
# --- Read back including the FormattedValue annotation ---
1393+
annotation = "OData.Community.Display.V1.FormattedValue"
1394+
retrieved = client.records.retrieve(
1395+
table_schema_name,
1396+
record_id,
1397+
select=["test_name", "test_status"],
1398+
include_annotations=annotation,
1399+
)
1400+
status_int = retrieved.get("test_status")
1401+
status_label = retrieved.get(f"test_status@{annotation}")
1402+
print(f" Retrieved: test_status={status_int}, formatted='{status_label}'")
1403+
assert status_int == TaskStatus.InProgress.value, f"expected {TaskStatus.InProgress.value}, got {status_int}"
1404+
1405+
# --- List records, filtering by the picklist column ---
1406+
completed = client.records.list(
1407+
table_schema_name,
1408+
select=["test_name", "test_status"],
1409+
filter=f"test_status eq {TaskStatus.Completed.value}",
1410+
include_annotations=annotation,
1411+
)
1412+
print(f"[OK] Query by picklist value found {len(completed)} 'Completed' record(s).")
1413+
1414+
except HttpError as e:
1415+
print(f"[ERR] HTTP error during picklist test: {e}")
1416+
raise
1417+
1418+
return table_schema_name
1419+
1420+
12631421
def _table_still_exists(client: DataverseClient, table_schema_name: Optional[str]) -> bool:
12641422
if not table_schema_name:
12651423
return False
@@ -1304,6 +1462,9 @@ def main():
13041462
# Test querying
13051463
test_query_records(client, table_info)
13061464

1465+
# Test picklist (local OptionSet) column creation, write, read
1466+
picklist_table_info = test_picklist_table(client)
1467+
13071468
# Test relationships
13081469
test_relationships(client)
13091470

@@ -1321,13 +1482,14 @@ def main():
13211482
print("[OK] Record Creation: Success")
13221483
print("[OK] Record Reading: Success")
13231484
print("[OK] Record Querying: Success")
1485+
print("[OK] Picklist Column: Success")
13241486
print("[OK] Relationship Operations: Success")
13251487
print("[OK] SQL Encoding: Success")
13261488
print("[OK] Batch Operations: Success")
13271489
print("\nYour PowerPlatform Dataverse Client SDK is fully functional!")
13281490

13291491
# Cleanup
1330-
cleanup_test_data(client, table_info, record_id)
1492+
cleanup_test_data(client, table_info, record_id, picklist_table_info)
13311493

13321494
except KeyboardInterrupt:
13331495
print("\n\n[WARN] Test interrupted by user")

0 commit comments

Comments
 (0)