From 3f864ec60464bd9ee40db15c2dc4af3aee6ac651 Mon Sep 17 00:00:00 2001 From: wmoore012 Date: Sun, 23 Nov 2025 03:02:51 -0500 Subject: [PATCH] style(bot): apply black formatting --- src/sql_safe/__init__.py | 10 ++-- src/sql_safe/exceptions.py | 103 +++++++++++++++------------------- src/sql_safe/safe_query.py | 4 +- src/sql_safe/validation.py | 112 ++++++++++++++++--------------------- 4 files changed, 97 insertions(+), 132 deletions(-) diff --git a/src/sql_safe/__init__.py b/src/sql_safe/__init__.py index 71dfa96..d4c77ef 100644 --- a/src/sql_safe/__init__.py +++ b/src/sql_safe/__init__.py @@ -22,22 +22,22 @@ ) __all__ = [ - "mysql_with_timeout", - "query", - "read_only_query", + "mysql_with_timeout", + "query", + "read_only_query", "get_engine", # Exceptions "SqlSafeError", "ValidationError", "ConfigurationError", - "ResourceError", + "ResourceError", "OperationError", "DatabaseConnectionError", "QueryExecutionError", "QueryTimeoutError", # Validation "validate_not_none", - "validate_string", + "validate_string", "validate_number", "validate_path", "validate_dict", diff --git a/src/sql_safe/exceptions.py b/src/sql_safe/exceptions.py index a77c08e..cfe6b97 100644 --- a/src/sql_safe/exceptions.py +++ b/src/sql_safe/exceptions.py @@ -15,16 +15,16 @@ class IcatSqlSafeError(Exception): """Base exception for all icat-sql-safe errors.""" - + def __init__( - self, - message: str, + self, + message: str, details: Optional[Dict[str, Any]] = None, - suggestion: Optional[str] = None + suggestion: Optional[str] = None, ) -> None: """ Initialize the exception with detailed error information. - + Args: message: Human-readable error message details: Additional error context and debugging information @@ -34,34 +34,30 @@ def __init__( self.message = message self.details = details or {} self.suggestion = suggestion - + def __str__(self) -> str: """Return formatted error message with details and suggestions.""" result = self.message - + if self.details: details_str = ", ".join(f"{k}={v}" for k, v in self.details.items()) result += f" (Details: {details_str})" - + if self.suggestion: result += f" Suggestion: {self.suggestion}" - + return result class ValidationError(IcatSqlSafeError): """Raised when input validation fails.""" - + def __init__( - self, - field: str, - value: Any, - expected: str, - suggestion: Optional[str] = None + self, field: str, value: Any, expected: str, suggestion: Optional[str] = None ) -> None: """ Initialize validation error with field-specific information. - + Args: field: Name of the field that failed validation value: The invalid value that was provided @@ -78,16 +74,11 @@ def __init__( class ConfigurationError(IcatSqlSafeError): """Raised when configuration is invalid or missing.""" - - def __init__( - self, - config_key: str, - issue: str, - suggestion: Optional[str] = None - ) -> None: + + def __init__(self, config_key: str, issue: str, suggestion: Optional[str] = None) -> None: """ Initialize configuration error. - + Args: config_key: The configuration key that has an issue issue: Description of the configuration problem @@ -102,17 +93,17 @@ def __init__( class ResourceError(IcatSqlSafeError): """Raised when system resources are unavailable or exhausted.""" - + def __init__( - self, - resource: str, + self, + resource: str, issue: str, current_usage: Optional[str] = None, - suggestion: Optional[str] = None + suggestion: Optional[str] = None, ) -> None: """ Initialize resource error. - + Args: resource: The resource that is unavailable (memory, disk, network, etc.) issue: Description of the resource problem @@ -131,17 +122,17 @@ def __init__( class OperationError(IcatSqlSafeError): """Raised when an operation fails due to business logic or external factors.""" - + def __init__( - self, - operation: str, + self, + operation: str, reason: str, retry_possible: bool = False, - suggestion: Optional[str] = None + suggestion: Optional[str] = None, ) -> None: """ Initialize operation error. - + Args: operation: The operation that failed reason: Why the operation failed @@ -158,18 +149,22 @@ def __init__( class DatabaseConnectionError(ResourceError): """Raised when database connection fails.""" - + def __init__( - self, + self, database_url: str, original_error: Optional[str] = None, - suggestion: Optional[str] = None + suggestion: Optional[str] = None, ) -> None: - issue = f"Failed to connect to database: {original_error}" if original_error else "Connection failed" + issue = ( + f"Failed to connect to database: {original_error}" + if original_error + else "Connection failed" + ) super().__init__( - "database_connection", - issue, - suggestion=suggestion or "Check database URL, credentials, and network connectivity" + "database_connection", + issue, + suggestion=suggestion or "Check database URL, credentials, and network connectivity", ) self.database_url = database_url self.original_error = original_error @@ -177,17 +172,12 @@ def __init__( class QueryExecutionError(OperationError): """Raised when SQL query execution fails.""" - - def __init__( - self, - query: str, - error_message: str, - suggestion: Optional[str] = None - ) -> None: + + def __init__(self, query: str, error_message: str, suggestion: Optional[str] = None) -> None: super().__init__( - "query_execution", + "query_execution", f"Query failed: {error_message}", - suggestion=suggestion or "Check query syntax and database permissions" + suggestion=suggestion or "Check query syntax and database permissions", ) self.query = query self.error_message = error_message @@ -195,17 +185,12 @@ def __init__( class QueryTimeoutError(TimeoutError): """Raised when SQL query times out.""" - - def __init__( - self, - query: str, - timeout_ms: int, - suggestion: Optional[str] = None - ) -> None: + + def __init__(self, query: str, timeout_ms: int, suggestion: Optional[str] = None) -> None: super().__init__( - timeout_ms / 1000, + timeout_ms / 1000, "query_execution", - suggestion or "Try optimizing the query or increasing timeout_ms" + suggestion or "Try optimizing the query or increasing timeout_ms", ) self.query = query self.timeout_ms = timeout_ms diff --git a/src/sql_safe/safe_query.py b/src/sql_safe/safe_query.py index d130230..9ac2d52 100644 --- a/src/sql_safe/safe_query.py +++ b/src/sql_safe/safe_query.py @@ -56,9 +56,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: elapsed_ms = (time.perf_counter() - start_time) * 1000 if elapsed_ms > ms: - logger.warning( - f"🐢 Slow query detected: {elapsed_ms:.1f}ms (threshold: {ms}ms)" - ) + logger.warning(f"🐢 Slow query detected: {elapsed_ms:.1f}ms (threshold: {ms}ms)") else: logger.debug(f"Query completed in {elapsed_ms:.1f}ms") diff --git a/src/sql_safe/validation.py b/src/sql_safe/validation.py index 2c592b7..14a1502 100644 --- a/src/sql_safe/validation.py +++ b/src/sql_safe/validation.py @@ -20,82 +20,76 @@ def validate_not_none(value: Any, field_name: str) -> Any: """ Validate that a value is not None. - + Args: value: The value to validate field_name: Name of the field for error messages - + Returns: The validated value - + Raises: ValidationError: If value is None """ if value is None: raise ValidationError( - field_name, - value, - "non-None value", - f"Provide a valid {field_name} value" + field_name, value, "non-None value", f"Provide a valid {field_name} value" ) return value def validate_string( - value: Any, - field_name: str, + value: Any, + field_name: str, min_length: int = 1, max_length: Optional[int] = None, - pattern: Optional[str] = None + pattern: Optional[str] = None, ) -> str: """ Validate that a value is a string with optional constraints. - + Args: value: The value to validate field_name: Name of the field for error messages min_length: Minimum string length (default: 1) max_length: Maximum string length (optional) pattern: Regex pattern the string must match (optional) - + Returns: The validated string - + Raises: ValidationError: If validation fails """ if not isinstance(value, str): raise ValidationError( - field_name, - value, - "string", - f"Convert {field_name} to string or provide string input" + field_name, value, "string", f"Convert {field_name} to string or provide string input" ) - + if len(value) < min_length: raise ValidationError( field_name, value, f"string with at least {min_length} characters", - f"Provide a longer {field_name} (current: {len(value)} chars)" + f"Provide a longer {field_name} (current: {len(value)} chars)", ) - + if max_length and len(value) > max_length: raise ValidationError( field_name, value, f"string with at most {max_length} characters", - f"Shorten {field_name} (current: {len(value)} chars, max: {max_length})" + f"Shorten {field_name} (current: {len(value)} chars, max: {max_length})", ) - + if pattern and not re.match(pattern, value): raise ValidationError( field_name, value, f"string matching pattern '{pattern}'", - f"Ensure {field_name} follows the required format" + f"Ensure {field_name} follows the required format", ) - + return value @@ -105,11 +99,11 @@ def validate_number( min_value: Optional[Union[int, float]] = None, max_value: Optional[Union[int, float]] = None, allow_zero: bool = True, - number_type: type = float + number_type: type = float, ) -> Union[int, float]: """ Validate that a value is a number with optional constraints. - + Args: value: The value to validate field_name: Name of the field for error messages @@ -117,10 +111,10 @@ def validate_number( max_value: Maximum allowed value (optional) allow_zero: Whether zero is allowed (default: True) number_type: Expected number type (int or float, default: float) - + Returns: The validated number - + Raises: ValidationError: If validation fails """ @@ -134,48 +128,45 @@ def validate_number( field_name, value, f"{number_type.__name__}", - f"Provide a valid numeric value for {field_name}" + f"Provide a valid numeric value for {field_name}", ) - + if not allow_zero and validated_value == 0: raise ValidationError( - field_name, - value, - "non-zero number", - f"Provide a non-zero value for {field_name}" + field_name, value, "non-zero number", f"Provide a non-zero value for {field_name}" ) - + if min_value is not None and validated_value < min_value: raise ValidationError( field_name, value, f"number >= {min_value}", - f"Increase {field_name} to at least {min_value}" + f"Increase {field_name} to at least {min_value}", ) - + if max_value is not None and validated_value > max_value: raise ValidationError( field_name, value, f"number <= {max_value}", - f"Reduce {field_name} to at most {max_value}" + f"Reduce {field_name} to at most {max_value}", ) - + return validated_value def validate_path(value: Any, field_name: str, must_exist: bool = False) -> Path: """ Validate that a value is a valid file path. - + Args: value: The value to validate field_name: Name of the field for error messages must_exist: Whether the path must exist on filesystem - + Returns: The validated Path object - + Raises: ValidationError: If validation fails """ @@ -183,20 +174,14 @@ def validate_path(value: Any, field_name: str, must_exist: bool = False) -> Path path = Path(value) except (TypeError, ValueError): raise ValidationError( - field_name, - value, - "valid file path", - f"Provide a valid path string for {field_name}" + field_name, value, "valid file path", f"Provide a valid path string for {field_name}" ) - + if must_exist and not path.exists(): raise ValidationError( - field_name, - value, - "existing file path", - f"Ensure the path exists: {path}" + field_name, value, "existing file path", f"Ensure the path exists: {path}" ) - + return path @@ -204,31 +189,28 @@ def validate_dict( value: Any, field_name: str, required_keys: Optional[List[str]] = None, - allowed_keys: Optional[List[str]] = None + allowed_keys: Optional[List[str]] = None, ) -> Dict[str, Any]: """ Validate that a value is a dictionary with optional key constraints. - + Args: value: The value to validate field_name: Name of the field for error messages required_keys: Keys that must be present (optional) allowed_keys: Only these keys are allowed (optional) - + Returns: The validated dictionary - + Raises: ValidationError: If validation fails """ if not isinstance(value, dict): raise ValidationError( - field_name, - value, - "dictionary", - f"Provide a dictionary for {field_name}" + field_name, value, "dictionary", f"Provide a dictionary for {field_name}" ) - + if required_keys: missing_keys = set(required_keys) - set(value.keys()) if missing_keys: @@ -236,9 +218,9 @@ def validate_dict( field_name, value, f"dictionary with keys: {required_keys}", - f"Add missing keys to {field_name}: {list(missing_keys)}" + f"Add missing keys to {field_name}: {list(missing_keys)}", ) - + if allowed_keys: extra_keys = set(value.keys()) - set(allowed_keys) if extra_keys: @@ -246,7 +228,7 @@ def validate_dict( field_name, value, f"dictionary with only allowed keys: {allowed_keys}", - f"Remove extra keys from {field_name}: {list(extra_keys)}" + f"Remove extra keys from {field_name}: {list(extra_keys)}", ) - + return value