Error Handling in pydapter¶
pydapter provides a comprehensive error handling system to help you diagnose and resolve issues when working with adapters. This document explains the exception hierarchy and how to handle errors effectively in your applications.
Exception Hierarchy¶
All pydapter exceptions inherit from the base AdapterError
class, which
provides context-rich error messages and a consistent interface for error
handling.
AdapterError
├── ValidationError
├── ParseError
├── ConnectionError
├── QueryError
├── ResourceError
├── ConfigurationError
└── AdapterNotFoundError
AdapterError¶
The base exception class for all pydapter errors. It provides a mechanism to attach context information to errors.
try:
# Some adapter operation
except AdapterError as e:
print(f"Error message: {e.message}")
print(f"Error context: {e.context}")
ValidationError¶
Raised when data validation fails, such as when required fields are missing or have incorrect types.
try:
model = MyModel.adapt_from(invalid_data, obj_key="json")
except ValidationError as e:
print(f"Validation failed: {e}")
print(f"Invalid data: {e.data}")
ParseError¶
Raised when data parsing fails, such as when trying to parse invalid JSON, CSV, or TOML.
try:
model = MyModel.adapt_from('{"invalid": json', obj_key="json")
except ParseError as e:
print(f"Parse error: {e}")
print(f"Source: {e.source}")
ConnectionError¶
Raised when a connection to a data source fails, such as when a database is unavailable.
try:
model = MyModel.adapt_from({"engine_url": "invalid://url", "table": "test"}, obj_key="sql")
except ConnectionError as e:
print(f"Connection failed: {e}")
print(f"Adapter: {e.adapter}")
print(f"URL: {e.url}")
QueryError¶
Raised when a query to a data source fails, such as when an SQL query contains errors.
try:
model = MyModel.adapt_from({"engine_url": "sqlite://", "table": "test", "query": "INVALID SQL"}, obj_key="sql")
except QueryError as e:
print(f"Query failed: {e}")
print(f"Query: {e.query}")
print(f"Adapter: {e.adapter}")
ResourceError¶
Raised when a resource (file, database table, etc.) cannot be accessed.
try:
model = MyModel.adapt_from(Path("nonexistent.json"), obj_key="json")
except ResourceError as e:
print(f"Resource error: {e}")
print(f"Resource: {e.resource}")
ConfigurationError¶
Raised when adapter configuration is invalid, such as when required parameters are missing.
try:
model = MyModel.adapt_from({"missing": "required_params"}, obj_key="sql")
except ConfigurationError as e:
print(f"Configuration error: {e}")
print(f"Config: {e.config}")
AdapterNotFoundError¶
Raised when an adapter is not found for a given obj_key
.
try:
model = MyModel.adapt_from({}, obj_key="nonexistent")
except AdapterNotFoundError as e:
print(f"Adapter not found: {e}")
print(f"Object key: {e.obj_key}")
Error Handling Best Practices¶
Catch Specific Exceptions¶
Catch the most specific exception type that applies to your situation:
try:
model = MyModel.adapt_from(data, obj_key="json")
except ParseError:
# Handle parsing errors
except ValidationError:
# Handle validation errors
except AdapterError:
# Handle any other adapter errors
Provide Context in Error Messages¶
When raising custom exceptions, provide as much context as possible:
raise ConnectionError(
"Failed to connect to database",
adapter="postgres",
url="postgresql://localhost:5432/mydb",
timeout=30
)
Handle Asynchronous Errors¶
For asynchronous adapters, use try/except blocks within async functions:
async def fetch_data():
try:
return await MyModel.adapt_from_async(data, obj_key="async_mongo")
except ConnectionError as e:
logger.error(f"Connection failed: {e}")
# Handle connection error
except AdapterError as e:
logger.error(f"Adapter error: {e}")
# Handle other adapter errors
Resource Cleanup¶
Ensure resources are properly cleaned up, even in error scenarios:
try:
# Some operation that acquires resources
result = perform_operation()
return result
except AdapterError:
# Handle the error
raise
finally:
# Clean up resources
cleanup_resources()
Common Error Scenarios and Solutions¶
JSON Parsing Errors¶
try:
model = MyModel.adapt_from(json_data, obj_key="json")
except ParseError as e:
if "Expecting property name" in str(e):
# Handle malformed JSON
elif "Expecting value" in str(e):
# Handle empty JSON
Database Connection Errors¶
try:
model = MyModel.adapt_from(db_config, obj_key="postgres")
except ConnectionError as e:
if "authentication failed" in str(e):
# Handle authentication issues
elif "connection refused" in str(e):
# Handle server unavailable
elif "database does not exist" in str(e):
# Handle missing database
Empty Result Sets¶
try:
model = MyModel.adapt_from(query_params, obj_key="mongo", many=False)
except ResourceError as e:
if "No documents found" in str(e):
# Handle empty result
return default_value
Conclusion¶
Proper error handling is essential for building robust applications with pydapter. By understanding the exception hierarchy and following best practices, you can create more resilient code that gracefully handles failure scenarios and provides clear feedback to users.