When generating Python code for the PowerPlatform-Dataverse-Client SDK, produce production-ready code that:
- Implements proper error handling with DataverseError hierarchy
- Uses singleton client pattern for connection management
- Includes retry logic with exponential backoff for 429/timeout errors
- Applies OData optimization (filter on server, select only needed columns)
- Implements logging for audit trails and debugging
- Includes type hints and docstrings
- Follows Microsoft best practices from official examples
from PowerPlatform.Dataverse.core.errors import (
DataverseError, ValidationError, MetadataError, HttpError
)
import logging
import time
logger = logging.getLogger(__name__)
def operation_with_retry(max_retries=3):
"""Function with retry logic."""
for attempt in range(max_retries):
try:
# Operation code
pass
except HttpError as e:
if attempt == max_retries - 1:
logger.error(f"Failed after {max_retries} attempts: {e}")
raise
backoff = 2 ** attempt
logger.warning(f"Attempt {attempt + 1} failed. Retrying in {backoff}s")
time.sleep(backoff)
Retry guidance:
- Exit the retry loop as soon as the operation succeeds, returning its result, so a successful call runs once.
- Retry only throttling, service unavailable, gateway timeout, and network or timeout errors; raise authentication, authorization, validation, and not found errors right away.
- Honor any retry delay the server sends, and add random jitter and a maximum delay.
- Retry creates and updates only when they are idempotent, such as an upsert by alternate key, or after a duplicate check.
- Verify import paths, exception classes, and error attributes such as status codes against the installed SDK version or official documentation before relying on them.
- Install the PowerPlatform-Dataverse-Client package by its exact name, pin a specific version, and confirm the package source with the user.
class DataverseService:
_instance = None
_client = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, org_url, credential):
if self._client is None:
self._client = DataverseClient(org_url, credential)
@property
def client(self):
return self._client
Client guidance:
- Prefer passing a client in explicitly, or keep one client per org URL and credential.
- Raise an error when the service is created again with a different org URL or credential, so calls always reach the intended environment.
- Guard instance and client creation with a lock, or use a shared factory function, so concurrent first calls create a single client.
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
logger.info(f"Created {count} records")
logger.warning(f"Record {id} not found")
logger.error(f"Operation failed: {error}")
Logging guidance:
- Library and module code only gets a named logger; place the root logging configuration in the application entry point.
- Use parameterized logging rather than formatted strings, in both this pattern and the retry template.
- Log the error type, status code, and correlation identifiers; keep response bodies, headers, record payloads, credentials, tokens, and personal data out of log messages.
- Sanitize user controlled values before logging them.
- Always include
select parameter to limit columns
- Use
filter on server (lowercase logical names)
- Use
orderby, top for pagination
- Use
expand for related records when available
- Keep untrusted input out of filter, orderby, select, and expand text until it has been validated
- Escape string literals by doubling single quotes
- Validate record identifiers, numbers, and dates by type before use
- Accept column and table logical names only from a fixed allow list
- Imports (stdlib, then third-party, then local)
- Constants and enums
- Logging configuration (application entry point only)
- Helper functions
- Main service classes
- Error handling classes
- Usage examples
When user asks to generate code, provide:
- Imports section with all required modules
- Configuration section with constants/enums
- Main implementation with proper error handling
- Docstrings explaining parameters and return values
- Type hints for all functions
- Usage example showing how to call the code
- Error scenarios with exception handling
- Logging statements for debugging
- ✅ All code must be syntactically correct Python 3.10+
- ✅ Must include try-except blocks for API calls
- ✅ Must use type hints for function parameters and return types
- ✅ Must include docstrings for all functions
- ✅ Must implement retry logic for transient failures
- ✅ Must use logger instead of print() for messages
- ✅ Must include configuration management (secrets, URLs): load the org URL and credentials from environment variables or a secret store, prefer managed identity or other token credentials over client secrets, keep secrets out of source code and committed config files, and use placeholders in usage examples
- ✅ Must follow PEP 8 style guidelines
- ✅ Bulk updates and deletes must support a dry run or require an explicit confirmation flag, and generated code should be tested in a test environment with least privilege security roles first
- ✅ Must include usage examples in comments