diff --git a/examples/advanced/file_upload.py b/examples/advanced/file_upload.py index 60f9495..d3499b7 100644 --- a/examples/advanced/file_upload.py +++ b/examples/advanced/file_upload.py @@ -167,7 +167,7 @@ def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)): if attempts > 1: retry_count = attempts - 1 print( - f" ↺ Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total." + f" [INFO] Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total." ) return result except Exception as ex: # noqa: BLE001 @@ -177,7 +177,7 @@ def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)): if attempts: retry_count = max(attempts - 1, 0) print( - f" ⚠ Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total." + f" [WARN] Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total." ) raise last diff --git a/examples/advanced/walkthrough.py b/examples/advanced/walkthrough.py index 7cad0e2..6016f3e 100644 --- a/examples/advanced/walkthrough.py +++ b/examples/advanced/walkthrough.py @@ -29,7 +29,7 @@ # Simple logging helper def log_call(description): - print(f"\n→ {description}") + print(f"\n-> {description}") # Define enum for priority picklist @@ -53,7 +53,7 @@ def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)): if attempts > 1: retry_count = attempts - 1 print( - f" ↺ Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total." + f" [INFO] Backoff succeeded after {retry_count} retry(s); waited {total_delay}s total." ) return result except Exception as ex: # noqa: BLE001 @@ -63,7 +63,7 @@ def backoff(op, *, delays=(0, 2, 5, 10, 20, 20)): if attempts: retry_count = max(attempts - 1, 0) print( - f" ⚠ Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total." + f" [WARN] Backoff exhausted after {retry_count} retry(s); waited {total_delay}s total." ) raise last @@ -92,7 +92,7 @@ def main(): log_call(f"DataverseClient(base_url='{base_url}', credential=...)") client = DataverseClient(base_url=base_url, credential=credential) - print(f"✓ Connected to: {base_url}") + print(f"[OK] Connected to: {base_url}") # ============================================================================ # 2. TABLE CREATION (METADATA) @@ -107,7 +107,7 @@ def main(): table_info = backoff(lambda: client.get_table_info(table_name)) if table_info: - print(f"✓ Table already exists: {table_info.get('table_schema_name')}") + print(f"[OK] Table already exists: {table_info.get('table_schema_name')}") print(f" Logical Name: {table_info.get('table_logical_name')}") print(f" Entity Set: {table_info.get('entity_set_name')}") else: @@ -120,7 +120,7 @@ def main(): "new_Priority": Priority, } table_info = backoff(lambda: client.create_table(table_name, columns)) - print(f"✓ Created table: {table_info.get('table_schema_name')}") + print(f"[OK] Created table: {table_info.get('table_schema_name')}") print(f" Columns created: {', '.join(table_info.get('columns_created', []))}") # ============================================================================ @@ -140,7 +140,7 @@ def main(): "new_Priority": Priority.MEDIUM, } id1 = backoff(lambda: client.create(table_name, single_record))[0] - print(f"✓ Created single record: {id1}") + print(f"[OK] Created single record: {id1}") # Multiple create log_call(f"client.create('{table_name}', [{{...}}, {{...}}, {{...}}])") @@ -168,7 +168,7 @@ def main(): }, ] ids = backoff(lambda: client.create(table_name, multiple_records)) - print(f"✓ Created {len(ids)} records: {ids}") + print(f"[OK] Created {len(ids)} records: {ids}") # ============================================================================ # 4. READ OPERATIONS @@ -180,7 +180,7 @@ def main(): # Single read by ID log_call(f"client.get('{table_name}', '{id1}')") record = backoff(lambda: client.get(table_name, id1)) - print("✓ Retrieved single record:") + print("[OK] Retrieved single record:") print( json.dumps( { @@ -202,7 +202,7 @@ def main(): records_iterator = backoff(lambda: client.get(table_name, filter="new_quantity gt 5")) for page in records_iterator: all_records.extend(page) - print(f"✓ Found {len(all_records)} records with new_quantity > 5") + print(f"[OK] Found {len(all_records)} records with new_quantity > 5") for rec in all_records: print(f" - new_Title='{rec.get('new_title')}', new_Quantity={rec.get('new_quantity')}") @@ -217,12 +217,12 @@ def main(): log_call(f"client.update('{table_name}', '{id1}', {{...}})") backoff(lambda: client.update(table_name, id1, {"new_Quantity": 100})) updated = backoff(lambda: client.get(table_name, id1)) - print(f"✓ Updated single record new_Quantity: {updated.get('new_quantity')}") + print(f"[OK] Updated single record new_Quantity: {updated.get('new_quantity')}") # Multiple update (broadcast same change) log_call(f"client.update('{table_name}', [{len(ids)} IDs], {{...}})") backoff(lambda: client.update(table_name, ids, {"new_Completed": True})) - print(f"✓ Updated {len(ids)} records to new_Completed=True") + print(f"[OK] Updated {len(ids)} records to new_Completed=True") # ============================================================================ # 6. PAGING DEMO @@ -244,7 +244,7 @@ def main(): for i in range(1, 21) ] paging_ids = backoff(lambda: client.create(table_name, paging_records)) - print(f"✓ Created {len(paging_ids)} records for paging demo") + print(f"[OK] Created {len(paging_ids)} records for paging demo") # Query with paging log_call(f"client.get('{table_name}', page_size=5)") @@ -265,11 +265,11 @@ def main(): sql = f"SELECT new_title, new_quantity FROM new_walkthroughdemo WHERE new_completed = 1" try: results = backoff(lambda: client.query_sql(sql)) - print(f"✓ SQL query returned {len(results)} completed records:") + print(f"[OK] SQL query returned {len(results)} completed records:") for result in results[:5]: # Show first 5 print(f" - new_Title='{result.get('new_title')}', new_Quantity={result.get('new_quantity')}") except Exception as e: - print(f"⚠ SQL query failed (known server-side bug): {str(e)}") + print(f"[WARN] SQL query failed (known server-side bug): {str(e)}") # ============================================================================ # 8. PICKLIST LABEL CONVERSION @@ -288,7 +288,7 @@ def main(): } label_id = backoff(lambda: client.create(table_name, label_record))[0] retrieved = backoff(lambda: client.get(table_name, label_id)) - print(f"✓ Created record with string label 'High' for new_Priority") + print(f"[OK] Created record with string label 'High' for new_Priority") print(f" new_Priority stored as integer: {retrieved.get('new_priority')}") print(f" new_Priority@FormattedValue: {retrieved.get('new_priority@OData.Community.Display.V1.FormattedValue')}") @@ -301,12 +301,12 @@ def main(): log_call(f"client.create_columns('{table_name}', {{'new_Notes': 'string'}})") created_cols = backoff(lambda: client.create_columns(table_name, {"new_Notes": "string"})) - print(f"✓ Added column: {created_cols[0]}") + print(f"[OK] Added column: {created_cols[0]}") # Delete the column we just added log_call(f"client.delete_columns('{table_name}', ['new_Notes'])") backoff(lambda: client.delete_columns(table_name, ["new_Notes"])) - print(f"✓ Deleted column: new_Notes") + print(f"[OK] Deleted column: new_Notes") # ============================================================================ # 10. DELETE OPERATIONS @@ -318,12 +318,12 @@ def main(): # Single delete log_call(f"client.delete('{table_name}', '{id1}')") backoff(lambda: client.delete(table_name, id1)) - print(f"✓ Deleted single record: {id1}") + print(f"[OK] Deleted single record: {id1}") # Multiple delete (delete the paging demo records) log_call(f"client.delete('{table_name}', [{len(paging_ids)} IDs])") job_id = backoff(lambda: client.delete(table_name, paging_ids)) - print(f"✓ Bulk delete job started: {job_id}") + print(f"[OK] Bulk delete job started: {job_id}") print(f" (Deleting {len(paging_ids)} paging demo records)") # ============================================================================ @@ -336,11 +336,11 @@ def main(): log_call(f"client.delete_table('{table_name}')") try: backoff(lambda: client.delete_table(table_name)) - print(f"✓ Deleted table: {table_name}") + print(f"[OK] Deleted table: {table_name}") except Exception as ex: # noqa: BLE001 code = getattr(getattr(ex, "response", None), "status_code", None) if (isinstance(ex, (requests.exceptions.HTTPError, MetadataError)) and code == 404): - print(f"✓ Table removed: {table_name}") + print(f"[OK] Table removed: {table_name}") else: raise @@ -351,16 +351,16 @@ def main(): print("Walkthrough Complete!") print("=" * 80) print("\nDemonstrated operations:") - print(" ✓ Table creation with multiple column types") - print(" ✓ Single and multiple record creation") - print(" ✓ Reading records by ID and with filters") - print(" ✓ Single and multiple record updates") - print(" ✓ Paging through large result sets") - print(" ✓ SQL queries") - print(" ✓ Picklist label-to-value conversion") - print(" ✓ Column management") - print(" ✓ Single and bulk delete operations") - print(" ✓ Table cleanup") + print(" [OK] Table creation with multiple column types") + print(" [OK] Single and multiple record creation") + print(" [OK] Reading records by ID and with filters") + print(" [OK] Single and multiple record updates") + print(" [OK] Paging through large result sets") + print(" [OK] SQL queries") + print(" [OK] Picklist label-to-value conversion") + print(" [OK] Column management") + print(" [OK] Single and bulk delete operations") + print(" [OK] Table cleanup") print("=" * 80) diff --git a/examples/basic/functional_testing.py b/examples/basic/functional_testing.py index 9d39eee..93f3c9d 100644 --- a/examples/basic/functional_testing.py +++ b/examples/basic/functional_testing.py @@ -37,23 +37,23 @@ def get_dataverse_org_url() -> str: """Get Dataverse org URL from user input.""" - print("\n🌐 Dataverse Environment Setup") + print("\n-> Dataverse Environment Setup") print("=" * 50) if not sys.stdin.isatty(): - print("❌ Interactive input required. Run this script in a terminal.") + print("[ERR] Interactive input required. Run this script in a terminal.") sys.exit(1) while True: org_url = input("Enter your Dataverse org URL (e.g., https://yourorg.crm.dynamics.com): ").strip() if org_url: return org_url.rstrip("/") - print("⚠️ Please enter a valid URL.") + print("[WARN] Please enter a valid URL.") def setup_authentication() -> DataverseClient: """Set up authentication and create Dataverse client.""" - print("\n🔐 Authentication Setup") + print("\n-> Authentication Setup") print("=" * 50) org_url = get_dataverse_org_url() @@ -62,14 +62,14 @@ def setup_authentication() -> DataverseClient: client = DataverseClient(org_url, credential) # Test the connection - print("🧪 Testing connection...") + print("Testing connection...") tables = client.list_tables() - print(f"✅ Connection successful! Found {len(tables)} tables.") + print(f"[OK] Connection successful! Found {len(tables)} tables.") return client except Exception as e: - print(f"❌ Authentication failed: {e}") - print("💡 Please check your credentials and permissions.") + print(f"[ERR] Authentication failed: {e}") + print("Please check your credentials and permissions.") sys.exit(1) @@ -92,7 +92,7 @@ def wait_for_table_metadata( if attempt > 1: print( - f" ✅ Table metadata available after {attempt} attempts." + f" [OK] Table metadata available after {attempt} attempts." ) return info except Exception: @@ -100,7 +100,7 @@ def wait_for_table_metadata( if attempt < retries: print( - f" ⏳ Waiting for table metadata to publish (attempt {attempt}/{retries})..." + f" Waiting for table metadata to publish (attempt {attempt}/{retries})..." ) time.sleep(delay_seconds) @@ -111,7 +111,7 @@ def wait_for_table_metadata( def ensure_test_table(client: DataverseClient) -> Dict[str, Any]: """Create or verify test table exists.""" - print("\n📋 Test Table Setup") + print("\n-> Test Table Setup") print("=" * 50) table_schema_name = "test_TestSDKFunctionality" @@ -120,14 +120,14 @@ def ensure_test_table(client: DataverseClient) -> Dict[str, Any]: # Check if table already exists existing_table = client.get_table_info(table_schema_name) if existing_table: - print(f"✅ Test table '{table_schema_name}' already exists") + print(f"[OK] Test table '{table_schema_name}' already exists") return existing_table except Exception: - print(f"📝 Table '{table_schema_name}' not found, creating...") + print(f"Table '{table_schema_name}' not found, creating...") try: - print("🔨 Creating new test table...") + print("Creating new test table...") # Create the test table with various field types table_info = client.create_table( table_schema_name, @@ -141,20 +141,20 @@ def ensure_test_table(client: DataverseClient) -> Dict[str, Any]: }, ) - print(f"✅ Created test table: {table_info.get('table_schema_name')}") + print(f"[OK] Created test table: {table_info.get('table_schema_name')}") print(f" Logical name: {table_info.get('table_logical_name')}") print(f" Entity set: {table_info.get('entity_set_name')}") return wait_for_table_metadata(client, table_schema_name) except MetadataError as e: - print(f"❌ Failed to create table: {e}") + print(f"[ERR] Failed to create table: {e}") sys.exit(1) def test_create_record(client: DataverseClient, table_info: Dict[str, Any]) -> str: """Test record creation.""" - print("\n📝 Record Creation Test") + print("\n-> Record Creation Test") print("=" * 50) table_schema_name = table_info.get("table_schema_name") @@ -173,18 +173,18 @@ def test_create_record(client: DataverseClient, table_info: Dict[str, Any]) -> s } try: - print("🚀 Creating test record...") + print("Creating test record...") created_ids: Optional[List[str]] = None for attempt in range(1, retries + 1): try: created_ids = client.create(table_schema_name, test_data) if attempt > 1: - print(f" ✅ Record creation succeeded after {attempt} attempts.") + print(f" [OK] Record creation succeeded after {attempt} attempts.") break except HttpError as err: if getattr(err, "status_code", None) == 404 and attempt < retries: print( - f" ⏳ Table not ready for create (attempt {attempt}/{retries}). Retrying in {delay_seconds}s..." + f" Table not ready for create (attempt {attempt}/{retries}). Retrying in {delay_seconds}s..." ) time.sleep(delay_seconds) continue @@ -192,7 +192,7 @@ def test_create_record(client: DataverseClient, table_info: Dict[str, Any]) -> s if isinstance(created_ids, list) and created_ids: record_id = created_ids[0] - print(f"✅ Record created successfully!") + print(f"[OK] Record created successfully!") print(f" Record ID: {record_id}") print(f" Name: {test_data[f'{attr_prefix}_name']}") return record_id @@ -200,16 +200,16 @@ def test_create_record(client: DataverseClient, table_info: Dict[str, Any]) -> s raise ValueError("Unexpected response from create operation") except HttpError as e: - print(f"❌ HTTP error during record creation: {e}") + print(f"[ERR] HTTP error during record creation: {e}") sys.exit(1) except Exception as e: - print(f"❌ Failed to create record: {e}") + print(f"[ERR] Failed to create record: {e}") sys.exit(1) def test_read_record(client: DataverseClient, table_info: Dict[str, Any], record_id: str) -> Dict[str, Any]: """Test record reading.""" - print("\n📖 Record Reading Test") + print("\n-> Record Reading Test") print("=" * 50) table_schema_name = table_info.get("table_schema_name") @@ -219,18 +219,18 @@ def test_read_record(client: DataverseClient, table_info: Dict[str, Any], record delay_seconds = 3 try: - print(f"🔍 Reading record: {record_id}") + print(f"Reading record: {record_id}") record = None for attempt in range(1, retries + 1): try: record = client.get(table_schema_name, record_id) if attempt > 1: - print(f" ✅ Record read succeeded after {attempt} attempts.") + print(f" [OK] Record read succeeded after {attempt} attempts.") break except HttpError as err: if getattr(err, "status_code", None) == 404 and attempt < retries: print( - f" ⏳ Record not queryable yet (attempt {attempt}/{retries}). Retrying in {delay_seconds}s..." + f" Record not queryable yet (attempt {attempt}/{retries}). Retrying in {delay_seconds}s..." ) time.sleep(delay_seconds) continue @@ -240,7 +240,7 @@ def test_read_record(client: DataverseClient, table_info: Dict[str, Any], record raise RuntimeError("Record did not become available in time.") if record: - print("✅ Record retrieved successfully!") + print("[OK] Record retrieved successfully!") print(" Retrieved data:") # Display key fields @@ -259,16 +259,16 @@ def test_read_record(client: DataverseClient, table_info: Dict[str, Any], record raise ValueError("Record not found") except HttpError as e: - print(f"❌ HTTP error during record reading: {e}") + print(f"[ERR] HTTP error during record reading: {e}") sys.exit(1) except Exception as e: - print(f"❌ Failed to read record: {e}") + print(f"[ERR] Failed to read record: {e}") sys.exit(1) def test_query_records(client: DataverseClient, table_info: Dict[str, Any]) -> None: """Test querying multiple records.""" - print("\n🔍 Record Query Test") + print("\n-> Record Query Test") print("=" * 50) table_schema_name = table_info.get("table_schema_name") @@ -277,7 +277,7 @@ def test_query_records(client: DataverseClient, table_info: Dict[str, Any]) -> N delay_seconds = 3 try: - print("🔍 Querying records from test table...") + print("Querying records from test table...") for attempt in range(1, retries + 1): try: records_iterator = client.get( @@ -297,25 +297,25 @@ def test_query_records(client: DataverseClient, table_info: Dict[str, Any]) -> N amount = record.get(f"{attr_prefix}_amount", "N/A") print(f" Record {record_count}: {name} (Count: {count}, Amount: {amount})") - print(f"✅ Query completed! Found {record_count} active records.") + print(f"[OK] Query completed! Found {record_count} active records.") break except HttpError as err: if getattr(err, "status_code", None) == 404 and attempt < retries: print( - f" ⏳ Query retry {attempt}/{retries} after metadata 404 ({err}). Waiting {delay_seconds}s..." + f" Query retry {attempt}/{retries} after metadata 404 ({err}). Waiting {delay_seconds}s..." ) time.sleep(delay_seconds) continue raise except Exception as e: - print(f"⚠️ Query test encountered an issue: {e}") + print(f"[WARN] Query test encountered an issue: {e}") print(" This might be expected if the table is very new.") def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], record_id: str) -> None: """Clean up test data.""" - print("\n🧹 Cleanup") + print("\n-> Cleanup") print("=" * 50) table_schema_name = table_info.get("table_schema_name") @@ -329,25 +329,25 @@ def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], recor for attempt in range(1, retries + 1): try: client.delete(table_schema_name, record_id) - print("✅ Test record deleted successfully") + print("[OK] Test record deleted successfully") break except HttpError as err: status = getattr(err, "status_code", None) if status == 404: - print("ℹ️ Record already deleted or not yet available; skipping.") + print("Record already deleted or not yet available; skipping.") break if attempt < retries: print( - f" ⏳ Record delete retry {attempt}/{retries} after error ({err}). Waiting {delay_seconds}s..." + f" Record delete retry {attempt}/{retries} after error ({err}). Waiting {delay_seconds}s..." ) time.sleep(delay_seconds) continue - print(f"⚠️ Failed to delete test record: {err}") + print(f"[WARN] Failed to delete test record: {err}") except Exception as e: - print(f"⚠️ Failed to delete test record: {e}") + print(f"[WARN] Failed to delete test record: {e}") break else: - print("ℹ️ Test record kept for inspection") + print("Test record kept for inspection") # Ask about table cleanup table_cleanup = input("Do you want to delete the test table? (y/N): ").strip().lower() @@ -356,7 +356,7 @@ def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], recor for attempt in range(1, retries + 1): try: client.delete_table(table_info.get("table_schema_name")) - print("✅ Test table deleted successfully") + print("[OK] Test table deleted successfully") break except HttpError as err: status = getattr(err, "status_code", None) @@ -364,26 +364,26 @@ def cleanup_test_data(client: DataverseClient, table_info: Dict[str, Any], recor if _table_still_exists(client, table_info.get("table_schema_name")): if attempt < retries: print( - f" ⏳ Table delete retry {attempt}/{retries} after metadata 404 ({err}). Waiting {delay_seconds}s..." + f" Table delete retry {attempt}/{retries} after metadata 404 ({err}). Waiting {delay_seconds}s..." ) time.sleep(delay_seconds) continue - print(f"⚠️ Failed to delete test table due to metadata delay: {err}") + print(f"[WARN] Failed to delete test table due to metadata delay: {err}") break - print("✅ Test table deleted successfully (404 reported).") + print("[OK] Test table deleted successfully (404 reported).") break if attempt < retries: print( - f" ⏳ Table delete retry {attempt}/{retries} after error ({err}). Waiting {delay_seconds}s..." + f" Table delete retry {attempt}/{retries} after error ({err}). Waiting {delay_seconds}s..." ) time.sleep(delay_seconds) continue - print(f"⚠️ Failed to delete test table: {err}") + print(f"[WARN] Failed to delete test table: {err}") except Exception as e: - print(f"⚠️ Failed to delete test table: {e}") + print(f"[WARN] Failed to delete test table: {e}") break else: - print("ℹ️ Test table kept for future testing") + print("Test table kept for future testing") def _table_still_exists(client: DataverseClient, table_schema_name: Optional[str]) -> bool: @@ -402,16 +402,16 @@ def _table_still_exists(client: DataverseClient, table_schema_name: Optional[str def main(): """Main test function.""" - print("🚀 PowerPlatform Dataverse Client SDK - Advanced Functional Testing") + print("PowerPlatform Dataverse Client SDK - Advanced Functional Testing") print("=" * 70) print("This script tests SDK functionality in a real Dataverse environment:") - print(" • Authentication & Connection") - print(" • Table Creation & Metadata Operations") - print(" • Record CRUD Operations") - print(" • Query Functionality") - print(" • Interactive Cleanup") + print(" - Authentication & Connection") + print(" - Table Creation & Metadata Operations") + print(" - Record CRUD Operations") + print(" - Query Functionality") + print(" - Interactive Cleanup") print("=" * 70) - print("💡 For installation validation, run examples/basic/installation_example.py first") + print("For installation validation, run examples/basic/installation_example.py first") print("=" * 70) try: @@ -429,24 +429,24 @@ def main(): test_query_records(client, table_info) # Success summary - print("\n🎉 Functional Test Summary") + print("\nFunctional Test Summary") print("=" * 50) - print("✅ Authentication: Success") - print("✅ Table Operations: Success") - print("✅ Record Creation: Success") - print("✅ Record Reading: Success") - print("✅ Record Querying: Success") - print("\n💡 Your PowerPlatform Dataverse Client SDK is fully functional!") + print("[OK] Authentication: Success") + print("[OK] Table Operations: Success") + print("[OK] Record Creation: Success") + print("[OK] Record Reading: Success") + print("[OK] Record Querying: Success") + print("\nYour PowerPlatform Dataverse Client SDK is fully functional!") # Cleanup cleanup_test_data(client, table_info, record_id) except KeyboardInterrupt: - print("\n\n⚠️ Test interrupted by user") + print("\n\n[WARN] Test interrupted by user") sys.exit(1) except Exception as e: - print(f"\n❌ Unexpected error: {e}") - print("💡 Please check your environment and try again") + print(f"\n[ERR] Unexpected error: {e}") + print("Please check your environment and try again") sys.exit(1) diff --git a/examples/basic/installation_example.py b/examples/basic/installation_example.py index 360dcd4..13ee785 100644 --- a/examples/basic/installation_example.py +++ b/examples/basic/installation_example.py @@ -35,18 +35,18 @@ - `pip install -e .` → Installs from local source code in "editable" mode **Editable Mode Benefits:** -- ✅ Changes to source code are immediately available (no reinstall needed) -- ✅ Perfect for development, testing, and contributing -- ✅ Examples and tests can access the local codebase -- ✅ Supports debugging and live code modifications +- Changes to source code are immediately available (no reinstall needed) +- Perfect for development, testing, and contributing +- Examples and tests can access the local codebase +- Supports debugging and live code modifications ## What This Script Does -- ✅ Validates package installation and imports -- ✅ Checks version and package metadata -- ✅ Shows code examples and usage patterns -- ✅ Offers optional interactive testing -- ✅ Provides troubleshooting guidance +- Validates package installation and imports +- Checks version and package metadata +- Shows code examples and usage patterns +- Offers optional interactive testing +- Provides troubleshooting guidance Prerequisites for Interactive Testing: - Access to a Microsoft Dataverse environment @@ -63,7 +63,7 @@ def validate_imports(): """Validate that all key imports work correctly.""" - print("🔍 Validating Package Imports...") + print("Validating Package Imports...") print("-" * 50) try: @@ -71,52 +71,52 @@ def validate_imports(): from PowerPlatform.Dataverse import __version__ from PowerPlatform.Dataverse.client import DataverseClient - print(f" ✅ Namespace: PowerPlatform.Dataverse") - print(f" ✅ Package version: {__version__}") - print(f" ✅ Client class: PowerPlatform.Dataverse.client.DataverseClient") + print(f" [OK] Namespace: PowerPlatform.Dataverse") + print(f" [OK] Package version: {__version__}") + print(f" [OK] Client class: PowerPlatform.Dataverse.client.DataverseClient") # Test submodule imports from PowerPlatform.Dataverse.core.errors import HttpError, MetadataError - print(f" ✅ Core errors: HttpError, MetadataError") + print(f" [OK] Core errors: HttpError, MetadataError") from PowerPlatform.Dataverse.core.config import DataverseConfig - print(f" ✅ Core config: DataverseConfig") + print(f" [OK] Core config: DataverseConfig") from PowerPlatform.Dataverse.data._odata import _ODataClient - print(f" ✅ Data layer: _ODataClient") + print(f" [OK] Data layer: _ODataClient") # Test Azure Identity import from azure.identity import InteractiveBrowserCredential - print(f" ✅ Azure Identity: InteractiveBrowserCredential") + print(f" [OK] Azure Identity: InteractiveBrowserCredential") return True, __version__, DataverseClient except ImportError as e: - print(f" ❌ Import failed: {e}") - print("\n💡 Troubleshooting:") - print(" 📦 For end users (published package):") - print(" • pip install PowerPlatform-Dataverse-Client") - print(" • pip install azure-identity") + print(f" [ERR] Import failed: {e}") + print("\nTroubleshooting:") + print(" For end users (published package):") + print(" - pip install PowerPlatform-Dataverse-Client") + print(" - pip install azure-identity") print(" ") - print(" 🛠️ For developers (local development):") - print(" • Navigate to the project root directory") - print(" • pip install -e .") - print(" • This enables 'editable mode' for live development") + print(" For developers (local development):") + print(" - Navigate to the project root directory") + print(" - pip install -e .") + print(" - This enables 'editable mode' for live development") print(" ") - print(" 🔧 General fixes:") - print(" • Check virtual environment is activated") - print(" • Verify you're in the correct directory") - print(" • Try: pip list | grep PowerPlatform") + print(" General fixes:") + print(" - Check virtual environment is activated") + print(" - Verify you're in the correct directory") + print(" - Try: pip list | grep PowerPlatform") return False, None, None def validate_client_methods(DataverseClient): """Validate that DataverseClient has expected methods.""" - print("\n🏗️ Validating Client Methods...") + print("\nValidating Client Methods...") print("-" * 50) expected_methods = [ @@ -134,9 +134,9 @@ def validate_client_methods(DataverseClient): missing_methods = [] for method in expected_methods: if hasattr(DataverseClient, method): - print(f" ✅ Method exists: {method}") + print(f" [OK] Method exists: {method}") else: - print(f" ❌ Method missing: {method}") + print(f" [ERR] Method missing: {method}") missing_methods.append(method) return len(missing_methods) == 0 @@ -144,7 +144,7 @@ def validate_client_methods(DataverseClient): def validate_package_metadata(): """Validate package metadata from pip.""" - print("\n📦 Validating Package Metadata...") + print("\nValidating Package Metadata...") print("-" * 50) try: @@ -156,26 +156,26 @@ def validate_package_metadata(): lines = result.stdout.split("\n") for line in lines: if any(line.startswith(prefix) for prefix in ["Name:", "Version:", "Summary:", "Location:"]): - print(f" ✅ {line}") + print(f" [OK] {line}") return True else: - print(f" ❌ Package not found in pip list") - print(" 💡 Try: pip install PowerPlatform-Dataverse-Client") + print(f" [ERR] Package not found in pip list") + print(" Try: pip install PowerPlatform-Dataverse-Client") return False except Exception as e: - print(f" ❌ Metadata validation failed: {e}") + print(f" [ERR] Metadata validation failed: {e}") return False def show_usage_examples(): """Display comprehensive usage examples.""" - print("\n📚 Usage Examples") + print("\nUsage Examples") print("=" * 50) print( """ -🔧 Basic Setup: +Basic Setup: ```python from PowerPlatform.Dataverse.client import DataverseClient from azure.identity import InteractiveBrowserCredential @@ -190,7 +190,7 @@ def show_usage_examples(): ) ``` -📝 CRUD Operations: +CRUD Operations: ```python # Create a record account_data = {"name": "Contoso Ltd", "telephone1": "555-0100"} @@ -208,7 +208,7 @@ def show_usage_examples(): client.delete("account", account_ids[0]) ``` -🔍 Querying Data: +Querying Data: ```python # Query with OData filter accounts = client.get("account", @@ -226,7 +226,7 @@ def show_usage_examples(): print(row['name']) ``` -🏗️ Table Management: +Table Management: ```python # Create custom table table_info = client.create_table("CustomEntity", { @@ -250,71 +250,71 @@ def show_usage_examples(): def interactive_test(): """Offer optional interactive testing with real Dataverse environment.""" - print("\n🧪 Interactive Testing") + print("\nInteractive Testing") print("=" * 50) choice = input("Would you like to test with a real Dataverse environment? (y/N): ").strip().lower() if choice not in ["y", "yes"]: - print(" ℹ️ Skipping interactive test") + print(" Skipping interactive test") return - print("\n🌐 Dataverse Environment Setup") + print("\nDataverse Environment Setup") print("-" * 50) if not sys.stdin.isatty(): - print(" ❌ Interactive input required for testing") + print(" [ERR] Interactive input required for testing") return org_url = input("Enter your Dataverse org URL (e.g., https://yourorg.crm.dynamics.com): ").strip() if not org_url: - print(" ⚠️ No URL provided, skipping test") + print(" [WARN] No URL provided, skipping test") return try: from PowerPlatform.Dataverse.client import DataverseClient from azure.identity import InteractiveBrowserCredential - print(" 🔐 Setting up authentication...") + print(" Setting up authentication...") credential = InteractiveBrowserCredential() - print(" 🚀 Creating client...") + print(" Creating client...") client = DataverseClient(org_url.rstrip("/"), credential) - print(" 🧪 Testing connection...") + print(" Testing connection...") tables = client.list_tables() - print(f" ✅ Connection successful!") - print(f" 📋 Found {len(tables)} tables in environment") - print(f" 🌐 Connected to: {org_url}") + print(f" [OK] Connection successful!") + print(f" Found {len(tables)} tables in environment") + print(f" Connected to: {org_url}") - print("\n 💡 Your SDK is ready for use!") - print(" 💡 Check the usage examples above for common patterns") + print("\n Your SDK is ready for use!") + print(" Check the usage examples above for common patterns") except Exception as e: - print(f" ❌ Interactive test failed: {e}") - print(" 💡 This might be due to authentication, network, or permissions") - print(" 💡 The SDK imports are still valid for offline development") + print(f" [ERR] Interactive test failed: {e}") + print(" This might be due to authentication, network, or permissions") + print(" The SDK imports are still valid for offline development") def main(): """Run comprehensive installation validation and demonstration.""" - print("🚀 PowerPlatform Dataverse Client SDK - Installation & Validation") + print("PowerPlatform Dataverse Client SDK - Installation & Validation") print("=" * 70) - print(f"🕒 Validation Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") + print(f"Validation Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("=" * 70) # Step 1: Validate imports imports_success, version, DataverseClient = validate_imports() if not imports_success: - print("\n❌ Import validation failed. Please check installation.") + print("\n[ERR] Import validation failed. Please check installation.") sys.exit(1) # Step 2: Validate client methods if DataverseClient: methods_success = validate_client_methods(DataverseClient) if not methods_success: - print("\n⚠️ Some client methods are missing, but basic functionality should work.") + print("\n[WARN] Some client methods are missing, but basic functionality should work.") # Step 3: Validate package metadata metadata_success = validate_package_metadata() @@ -327,7 +327,7 @@ def main(): # Summary print("\n" + "=" * 70) - print("📊 VALIDATION SUMMARY") + print("VALIDATION SUMMARY") print("=" * 70) results = [ @@ -338,37 +338,37 @@ def main(): all_passed = True for test_name, success in results: - status = "✅ PASS" if success else "❌ FAIL" + status = "[OK] PASS" if success else "[ERR] FAIL" print(f"{test_name:<20} {status}") if not success: all_passed = False print("=" * 70) if all_passed: - print("🎉 SUCCESS: PowerPlatform-Dataverse-Client is properly installed!") + print("SUCCESS: PowerPlatform-Dataverse-Client is properly installed!") if version: - print(f"📦 Package Version: {version}") - print("\n💡 What this validates:") - print(" ✅ Package installation is correct") - print(" ✅ All namespace imports work") - print(" ✅ Client classes are accessible") - print(" ✅ Package metadata is valid") - print(" ✅ Ready for development and production use") - - print(f"\n🎯 Next Steps:") - print(" • Review the usage examples above") - print(" • Configure your Azure Identity credentials") - print(" • Start building with PowerPlatform.Dataverse!") + print(f"Package Version: {version}") + print("\nWhat this validates:") + print(" - Package installation is correct") + print(" - All namespace imports work") + print(" - Client classes are accessible") + print(" - Package metadata is valid") + print(" - Ready for development and production use") + + print(f"\nNext Steps:") + print(" - Review the usage examples above") + print(" - Configure your Azure Identity credentials") + print(" - Start building with PowerPlatform.Dataverse!") else: - print("❌ Some validation checks failed!") - print("💡 Review the errors above and reinstall if needed:") + print("[ERR] Some validation checks failed!") + print("Review the errors above and reinstall if needed:") print(" pip uninstall PowerPlatform-Dataverse-Client") print(" pip install PowerPlatform-Dataverse-Client") sys.exit(1) if __name__ == "__main__": - print("🚀 PowerPlatform-Dataverse-Client SDK Installation Example") + print("PowerPlatform-Dataverse-Client SDK Installation Example") print("=" * 60) main() diff --git a/src/PowerPlatform/Dataverse/data/_odata.py b/src/PowerPlatform/Dataverse/data/_odata.py index df78185..7c5fc6c 100644 --- a/src/PowerPlatform/Dataverse/data/_odata.py +++ b/src/PowerPlatform/Dataverse/data/_odata.py @@ -36,7 +36,6 @@ from ..__version__ import __version__ as _SDK_VERSION - _USER_AGENT = f"DataverseSvcPythonClient:{_SDK_VERSION}" _GUID_RE = re.compile(r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}") _CALL_SCOPE_CORRELATION_ID: ContextVar[Optional[str]] = ContextVar("_CALL_SCOPE_CORRELATION_ID", default=None)