Pony Object-Relational Mapper for Python with Pythonic query syntax using generator expressions
—
Comprehensive exception hierarchy covering database errors, ORM-specific errors, query errors, and transaction errors. Proper exception handling is crucial for building robust applications with Pony ORM.
Core ORM exceptions that handle entity operations, queries, and object lifecycle errors.
class OrmError(Exception):
"""Base exception class for all ORM-related errors."""
class ObjectNotFound(OrmError):
"""Raised when get() or [] operator finds no matching entity."""
class MultipleObjectsFoundError(OrmError):
"""Raised when get() finds multiple entities when expecting one."""
class TooManyObjectsFoundError(MultipleObjectsFoundError):
"""Raised when query returns more objects than expected limit."""
class OperationWithDeletedObjectError(OrmError):
"""Raised when attempting operations on deleted entity objects."""
class CacheIndexError(OrmError):
"""Raised when entity cache index operations fail."""
class MappingError(OrmError):
"""Raised when entity mapping or schema definition is invalid."""
class ERDiagramError(OrmError):
"""Raised when entity relationship diagram generation fails."""
class BindingError(OrmError):
"""Raised when database binding or connection configuration fails."""Standard database API exceptions that correspond to DB-API 2.0 specification errors.
class DBException(Exception):
"""Base exception class for all database-related errors."""
class Warning(DBException):
"""Exception for important database warnings."""
class Error(DBException):
"""Base exception class for database errors."""
class InterfaceError(Error):
"""Exception for database interface errors."""
class DatabaseError(Error):
"""Exception for database-specific errors."""
class DataError(DatabaseError):
"""Exception for data processing errors (invalid data, numeric overflow, etc.)."""
class OperationalError(DatabaseError):
"""Exception for database operation errors (connection lost, memory allocation, etc.)."""
class IntegrityError(DatabaseError):
"""Exception for database constraint violations (foreign key, unique, etc.)."""
class InternalError(DatabaseError):
"""Exception for internal database errors."""
class ProgrammingError(DatabaseError):
"""Exception for programming errors (table not found, syntax error, etc.)."""
class NotSupportedError(DatabaseError):
"""Exception for unsupported database operations or methods."""Exceptions related to database schema operations and table management.
class DBSchemaError(OrmError):
"""Raised when database schema operations fail."""
class TableDoesNotExist(DBSchemaError):
"""Raised when referencing non-existent database table."""
class TableIsNotEmpty(DBSchemaError):
"""Raised when attempting operations that require empty table."""
class ConstraintError(DBSchemaError):
"""Raised when database constraint operations fail."""Exceptions specific to query operations and result processing.
class RowNotFound(DBException):
"""Raised when database query returns no rows when expecting results."""
class MultipleRowsFound(DBException):
"""Raised when database query returns multiple rows when expecting one."""
class TooManyRowsFound(MultipleRowsFound):
"""Raised when query returns more rows than specified limit."""Exceptions related to transaction management and concurrency control.
class TransactionError(OrmError):
"""Base exception class for transaction-related errors."""
class ConnectionClosedError(TransactionError):
"""Raised when database connection is unexpectedly closed."""
class TransactionIntegrityError(TransactionError):
"""Raised when transaction integrity is compromised."""
class IsolationError(TransactionError):
"""Raised when transaction isolation level conflicts occur."""
class CommitException(TransactionError):
"""Raised when transaction commit operation fails."""
class RollbackException(TransactionError):
"""Raised when transaction rollback operation fails."""
class UnrepeatableReadError(TransactionError):
"""Raised when repeatable read isolation is violated."""
class OptimisticCheckError(TransactionError):
"""Raised when optimistic concurrency control check fails."""
class UnresolvableCyclicDependency(TransactionError):
"""Raised when circular dependencies prevent transaction completion."""
class UnexpectedError(TransactionError):
"""Raised for unexpected transaction-related errors."""
class DatabaseSessionIsOver(TransactionError):
"""Raised when attempting operations outside active database session."""Exceptions related to query translation and runtime operations.
class TranslationError(OrmError):
"""Raised when generator expression cannot be translated to SQL."""
class ExprEvalError(OrmError):
"""Raised when expression evaluation fails during query processing."""
class PonyRuntimeWarning(UserWarning):
"""Warning class for runtime issues that don't prevent execution."""
class DatabaseContainsIncorrectValue(PonyRuntimeWarning):
"""Warning when database contains values that don't match expected format."""
class DatabaseContainsIncorrectEmptyValue(PonyRuntimeWarning):
"""Warning when database contains empty values in unexpected contexts."""Exceptions related to security and access control operations.
class PermissionError(OrmError):
"""Raised when security permission checks fail."""from pony.orm import *
@db_session
def safe_user_lookup(email):
try:
user = User.get(email=email)
return user
except ObjectNotFound:
print(f"No user found with email: {email}")
return None
except MultipleObjectsFoundError:
print(f"Multiple users found with email: {email}")
# This shouldn't happen if email is unique
raise
@db_session
def handle_entity_operations():
try:
# Try to create user
user = User(name="Alice", email="alice@example.com")
commit()
except IntegrityError as e:
print(f"Database constraint violation: {e}")
rollback()
# Handle duplicate email, etc.
except DatabaseError as e:
print(f"Database error occurred: {e}")
rollback()
raise@db_session
def handle_transaction_errors():
try:
# Risky operations that might conflict
user = User.get(name="Alice")
user.balance += 100
# Force a flush to detect conflicts early
flush()
# More operations...
order = Order(user=user, total=50.0)
commit()
except OptimisticCheckError as e:
print(f"Concurrent modification detected: {e}")
rollback()
# Retry logic or user notification
except ConnectionClosedError as e:
print(f"Database connection lost: {e}")
# Reconnection logic
except TransactionError as e:
print(f"Transaction failed: {e}")
rollback()
raise
# Retry pattern for handling optimistic concurrency
def retry_on_conflict(func, max_retries=3):
for attempt in range(max_retries):
try:
return func()
except OptimisticCheckError:
if attempt == max_retries - 1:
raise
print(f"Retry attempt {attempt + 1}")
# Brief delay before retry
import time
time.sleep(0.1 * (attempt + 1))@db_session
def safe_query_operations():
try:
# Query that might return no results
admin = User.get(role="admin")
except ObjectNotFound:
print("No admin user found, creating default admin")
admin = User(name="Admin", role="admin", email="admin@example.com")
try:
# Query that might return multiple results unexpectedly
primary_contact = Contact.get(is_primary=True, company_id=123)
except MultipleObjectsFoundError:
print("Multiple primary contacts found, using first one")
primary_contact = Contact.select(
lambda c: c.is_primary and c.company_id == 123
).first()
except ObjectNotFound:
print("No primary contact found")
primary_contact = None
# Handle translation errors for complex queries
@db_session
def handle_query_translation():
try:
# Complex query that might not translate properly
result = select(u for u in User
if some_complex_python_function(u.data))
except TranslationError as e:
print(f"Query cannot be translated to SQL: {e}")
# Fall back to Python filtering
all_users = User.select()
result = [u for u in all_users
if some_complex_python_function(u.data)]def handle_database_setup():
try:
db.bind('postgresql', host='localhost', user='app', password='secret')
db.generate_mapping(create_tables=True)
except BindingError as e:
print(f"Failed to bind to database: {e}")
# Try fallback database
db.bind('sqlite', filename='fallback.db')
db.generate_mapping(create_tables=True)
except TableDoesNotExist as e:
print(f"Required table missing: {e}")
# Create missing tables
db.create_tables()
except DBSchemaError as e:
print(f"Schema error: {e}")
# Handle schema migration or recreation
except DatabaseError as e:
print(f"Database operation failed: {e}")
raise
@db_session
def handle_table_operations():
try:
# Operation that requires empty table
db.execute("TRUNCATE TABLE user_sessions")
except TableIsNotEmpty as e:
print(f"Cannot truncate non-empty table: {e}")
# Delete rows individually
delete(s for s in UserSession)
except ProgrammingError as e:
print(f"SQL programming error: {e}")
# Handle SQL syntax issuesfrom functools import wraps
def safe_db_operation(func):
"""Decorator for comprehensive database error handling."""
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except ObjectNotFound as e:
print(f"Entity not found in {func.__name__}: {e}")
return None
except MultipleObjectsFoundError as e:
print(f"Multiple entities found in {func.__name__}: {e}")
raise
except IntegrityError as e:
print(f"Database constraint violation in {func.__name__}: {e}")
rollback()
raise
except OptimisticCheckError as e:
print(f"Concurrent modification in {func.__name__}: {e}")
rollback()
raise
except TransactionError as e:
print(f"Transaction error in {func.__name__}: {e}")
rollback()
raise
except DatabaseError as e:
print(f"Database error in {func.__name__}: {e}")
rollback()
raise
except Exception as e:
print(f"Unexpected error in {func.__name__}: {e}")
rollback()
raise
return wrapper
# Usage of the decorator
@safe_db_operation
@db_session
def update_user_profile(user_id, **updates):
user = User[user_id] # May raise ObjectNotFound
for key, value in updates.items():
setattr(user, key, value)
commit()
return userimport warnings
# Handle runtime warnings
def handle_warnings():
# Catch Pony runtime warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
with db_session:
# Operations that might generate warnings
problematic_data = select(u for u in User if u.data_field)
for warning in w:
if issubclass(warning.category, PonyRuntimeWarning):
print(f"Pony warning: {warning.message}")
# Handle data quality issues
@db_session
def handle_expression_errors():
try:
# Complex expression that might fail evaluation
result = select(u.calculate_score() for u in User)
except ExprEvalError as e:
print(f"Expression evaluation failed: {e}")
# Fall back to safer calculation
result = select(u for u in User)
scores = [u.calculate_score() for u in result]