Skip to content

Commit 7bfd93d

Browse files
tpellissierclaude
andcommitted
Add fluent .with_response_details() API for telemetry access
Phase 1 SDK restructure: All methods return OperationResult with fluent .with_response_details() API for optional telemetry access. Changes: - Add OperationResult wrapper with dunder methods for transparent behavior - Add RequestTelemetryData and DataverseResponse result types - Unwrap OperationResult in update/delete to allow operation chaining - Rename internal type alias to _ODataRequestResult for clarity - Standardize all _odata.py method return type annotations - Add telemetry printing to walkthrough example Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 09ff1fe commit 7bfd93d

7 files changed

Lines changed: 1034 additions & 253 deletions

File tree

examples/advanced/walkthrough.py

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ def log_call(description):
3232
print(f"\n-> {description}")
3333

3434

35+
def print_telemetry(telemetry):
36+
"""Print telemetry IDs from a response."""
37+
print(f" Telemetry:")
38+
print(f" client_request_id: {telemetry.get('client_request_id')}")
39+
print(f" correlation_id: {telemetry.get('correlation_id')}")
40+
print(f" service_request_id: {telemetry.get('service_request_id')}")
41+
42+
3543
# Define enum for priority picklist
3644
class Priority(IntEnum):
3745
LOW = 1
@@ -52,19 +60,15 @@ def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)):
5260
result = op()
5361
if attempts > 1:
5462
retry_count = attempts - 1
55-
print(
56-
f" [INFO] Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total."
57-
)
63+
print(f" [INFO] Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total.")
5864
return result
5965
except Exception as ex: # noqa: BLE001
6066
last = ex
6167
continue
6268
if last:
6369
if attempts:
6470
retry_count = max(attempts - 1, 0)
65-
print(
66-
f" [WARN] Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total."
67-
)
71+
print(f" [WARN] Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total.")
6872
raise last
6973

7074

@@ -104,12 +108,13 @@ def main():
104108
table_name = "new_WalkthroughDemo"
105109

106110
log_call(f"client.get_table_info('{table_name}')")
107-
table_info = backoff(lambda: client.get_table_info(table_name))
111+
table_info_result = backoff(lambda: client.get_table_info(table_name))
112+
print_telemetry(table_info_result.with_response_details().telemetry)
108113

109-
if table_info:
110-
print(f"[OK] Table already exists: {table_info.get('table_schema_name')}")
111-
print(f" Logical Name: {table_info.get('table_logical_name')}")
112-
print(f" Entity Set: {table_info.get('entity_set_name')}")
114+
if table_info_result.value:
115+
print(f"[OK] Table already exists: {table_info_result.get('table_schema_name')}")
116+
print(f" Logical Name: {table_info_result.get('table_logical_name')}")
117+
print(f" Entity Set: {table_info_result.get('entity_set_name')}")
113118
else:
114119
log_call(f"client.create_table('{table_name}', columns={{...}})")
115120
columns = {
@@ -119,9 +124,10 @@ def main():
119124
"new_Completed": "bool",
120125
"new_Priority": Priority,
121126
}
122-
table_info = backoff(lambda: client.create_table(table_name, columns))
123-
print(f"[OK] Created table: {table_info.get('table_schema_name')}")
124-
print(f" Columns created: {', '.join(table_info.get('columns_created', []))}")
127+
table_info_result = backoff(lambda: client.create_table(table_name, columns))
128+
print(f"[OK] Created table: {table_info_result.get('table_schema_name')}")
129+
print(f" Columns created: {', '.join(table_info_result.get('columns_created', []))}")
130+
print_telemetry(table_info_result.with_response_details().telemetry)
125131

126132
# ============================================================================
127133
# 3. CREATE OPERATIONS
@@ -139,8 +145,10 @@ def main():
139145
"new_Completed": False,
140146
"new_Priority": Priority.MEDIUM,
141147
}
142-
id1 = backoff(lambda: client.create(table_name, single_record))[0]
148+
create_result = backoff(lambda: client.create(table_name, single_record))
149+
id1 = create_result[0]
143150
print(f"[OK] Created single record: {id1}")
151+
print_telemetry(create_result.with_response_details().telemetry)
144152

145153
# Multiple create
146154
log_call(f"client.create('{table_name}', [{{...}}, {{...}}, {{...}}])")
@@ -169,6 +177,7 @@ def main():
169177
]
170178
ids = backoff(lambda: client.create(table_name, multiple_records))
171179
print(f"[OK] Created {len(ids)} records: {ids}")
180+
print_telemetry(ids.with_response_details().telemetry)
172181

173182
# ============================================================================
174183
# 4. READ OPERATIONS
@@ -195,6 +204,7 @@ def main():
195204
indent=2,
196205
)
197206
)
207+
print_telemetry(record.with_response_details().telemetry)
198208

199209
# Multiple read with filter
200210
log_call(f"client.get('{table_name}', filter='new_quantity gt 5')")
@@ -215,14 +225,16 @@ def main():
215225

216226
# Single update
217227
log_call(f"client.update('{table_name}', '{id1}', {{...}})")
218-
backoff(lambda: client.update(table_name, id1, {"new_Quantity": 100}))
228+
update_result = backoff(lambda: client.update(table_name, id1, {"new_Quantity": 100}))
219229
updated = backoff(lambda: client.get(table_name, id1))
220230
print(f"[OK] Updated single record new_Quantity: {updated.get('new_quantity')}")
231+
print_telemetry(update_result.with_response_details().telemetry)
221232

222233
# Multiple update (broadcast same change)
223234
log_call(f"client.update('{table_name}', [{len(ids)} IDs], {{...}})")
224-
backoff(lambda: client.update(table_name, ids, {"new_Completed": True}))
235+
multi_update_result = backoff(lambda: client.update(table_name, ids, {"new_Completed": True}))
225236
print(f"[OK] Updated {len(ids)} records to new_Completed=True")
237+
print_telemetry(multi_update_result.with_response_details().telemetry)
226238

227239
# ============================================================================
228240
# 6. PAGING DEMO
@@ -245,6 +257,7 @@ def main():
245257
]
246258
paging_ids = backoff(lambda: client.create(table_name, paging_records))
247259
print(f"[OK] Created {len(paging_ids)} records for paging demo")
260+
print_telemetry(paging_ids.with_response_details().telemetry)
248261

249262
# Query with paging
250263
log_call(f"client.get('{table_name}', page_size=5)")
@@ -264,10 +277,11 @@ def main():
264277
log_call(f"client.query_sql('SELECT new_title, new_quantity FROM {table_name} WHERE new_completed = 1')")
265278
sql = f"SELECT new_title, new_quantity FROM new_walkthroughdemo WHERE new_completed = 1"
266279
try:
267-
results = backoff(lambda: client.query_sql(sql))
268-
print(f"[OK] SQL query returned {len(results)} completed records:")
269-
for result in results[:5]: # Show first 5
280+
sql_result = backoff(lambda: client.query_sql(sql))
281+
print(f"[OK] SQL query returned {len(sql_result)} completed records:")
282+
for result in sql_result[:5]: # Show first 5
270283
print(f" - new_Title='{result.get('new_title')}', new_Quantity={result.get('new_quantity')}")
284+
print_telemetry(sql_result.with_response_details().telemetry)
271285
except Exception as e:
272286
print(f"[WARN] SQL query failed (known server-side bug): {str(e)}")
273287

@@ -286,11 +300,13 @@ def main():
286300
"new_Completed": False,
287301
"new_Priority": "High", # String label instead of int
288302
}
289-
label_id = backoff(lambda: client.create(table_name, label_record))[0]
303+
label_create_result = backoff(lambda: client.create(table_name, label_record))
304+
label_id = label_create_result[0]
290305
retrieved = backoff(lambda: client.get(table_name, label_id))
291306
print(f"[OK] Created record with string label 'High' for new_Priority")
292307
print(f" new_Priority stored as integer: {retrieved.get('new_priority')}")
293308
print(f" new_Priority@FormattedValue: {retrieved.get('new_priority@OData.Community.Display.V1.FormattedValue')}")
309+
print_telemetry(label_create_result.with_response_details().telemetry)
294310

295311
# ============================================================================
296312
# 9. COLUMN MANAGEMENT
@@ -302,11 +318,13 @@ def main():
302318
log_call(f"client.create_columns('{table_name}', {{'new_Notes': 'string'}})")
303319
created_cols = backoff(lambda: client.create_columns(table_name, {"new_Notes": "string"}))
304320
print(f"[OK] Added column: {created_cols[0]}")
321+
print_telemetry(created_cols.with_response_details().telemetry)
305322

306323
# Delete the column we just added
307324
log_call(f"client.delete_columns('{table_name}', ['new_Notes'])")
308-
backoff(lambda: client.delete_columns(table_name, ["new_Notes"]))
325+
delete_cols_result = backoff(lambda: client.delete_columns(table_name, ["new_Notes"]))
309326
print(f"[OK] Deleted column: new_Notes")
327+
print_telemetry(delete_cols_result.with_response_details().telemetry)
310328

311329
# ============================================================================
312330
# 10. DELETE OPERATIONS
@@ -317,14 +335,16 @@ def main():
317335

318336
# Single delete
319337
log_call(f"client.delete('{table_name}', '{id1}')")
320-
backoff(lambda: client.delete(table_name, id1))
338+
delete_result = backoff(lambda: client.delete(table_name, id1))
321339
print(f"[OK] Deleted single record: {id1}")
340+
print_telemetry(delete_result.with_response_details().telemetry)
322341

323342
# Multiple delete (delete the paging demo records)
324343
log_call(f"client.delete('{table_name}', [{len(paging_ids)} IDs])")
325344
job_id = backoff(lambda: client.delete(table_name, paging_ids))
326345
print(f"[OK] Bulk delete job started: {job_id}")
327346
print(f" (Deleting {len(paging_ids)} paging demo records)")
347+
print_telemetry(job_id.with_response_details().telemetry)
328348

329349
# ============================================================================
330350
# 11. CLEANUP
@@ -335,11 +355,12 @@ def main():
335355

336356
log_call(f"client.delete_table('{table_name}')")
337357
try:
338-
backoff(lambda: client.delete_table(table_name))
358+
delete_table_result = backoff(lambda: client.delete_table(table_name))
339359
print(f"[OK] Deleted table: {table_name}")
360+
print_telemetry(delete_table_result.with_response_details().telemetry)
340361
except Exception as ex: # noqa: BLE001
341362
code = getattr(getattr(ex, "response", None), "status_code", None)
342-
if (isinstance(ex, (requests.exceptions.HTTPError, MetadataError)) and code == 404):
363+
if isinstance(ex, (requests.exceptions.HTTPError, MetadataError)) and code == 404:
343364
print(f"[OK] Table removed: {table_name}")
344365
else:
345366
raise

0 commit comments

Comments
 (0)