error.py
Overview
The [error.py](/projects/286/67543) module provides a structured and extensible mechanism for handling operating system errors (errno) by creating specific exception classes dynamically based on the POSIX `errno` values. This approach allows the program to raise and catch meaningful, errno-specific exceptions rather than generic `OSError` or [EnvironmentError](/projects/286/67579) exceptions.
Key features include:
Defining a base
Errorclass that extends EnvironmentError with enhanced string representation.An
ErrorMakerclass that lazily generates and caches exception classes for each errno code.A
checked_callutility function that wraps calls to system or IO functions and raises the appropriate errno-specific exception on failure.Special handling and mapping of Windows-specific error codes to corresponding POSIX errno.
Dynamic attribute access to fetch errno classes by name.
This module is useful in larger systems dealing with OS-level IO or filesystem operations, making error handling more precise and expressive.
Classes and Functions
Class: Error
A subclass of [EnvironmentError](/projects/286/67579) that represents an OS error corresponding to a specific errno. It provides customized string and representation methods for clearer debugging messages.
Methods:
__repr__(self) -> strReturns a detailed string representation of the error including its module, class name, docstring (description), and constructor arguments.
Example:
err = Error("File not found") print(repr(err)) # Output: # py.error.Error 'No such file or directory': File not found__str__(self) -> strReturns a concise, human-readable string with the error description and arguments.
Example:
err = Error("File not found") print(str(err)) # Output: # [No such file or directory]: File not found
Class: ErrorMaker
A factory class that lazily creates and caches custom exception classes for each errno defined in the POSIX standard (`errno` module). Each generated class:
Subclasses
Error.Has a dynamic name matching the errno symbolic name (e.g.,
ENOENT).Contains a docstring describing the error (
os.strerror(eno)).
This class also provides a utility to call functions and automatically raise the appropriate errno-specific exception on failure.
Attributes:
_errno2class: dict[int, type[Error]]Cache mapping errno integer values to their dynamically created exception classes.
Methods:
__getattr__(self, name: str) -> type[Error]Lazily fetches or creates an error class based on the errno symbolic name.
Raises
AttributeErrorif the attribute name starts with an underscore.Example:
err_class = error_maker.ENOENT print(err_class) # <class 'py.error.ENOENT'>_geterrnoclass(self, eno: int) -> type[Error]Internal method that returns the cached error class for a given errno number. If it doesn’t exist, creates one dynamically.
checked_call(self, func: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> RCalls the provided function with the given arguments. If the function raises an
OSErrororError, it converts the exception into the appropriate errno-specific error class and re-raises it.Handles Windows-specific error codes by mapping them to POSIX errno equivalents.
Parameters:
func: The callable to invoke.*args: Positional arguments for the callable.**kwargs: Keyword arguments for the callable.
**Returns:**
The return value of
funcif no exception occurs.
**Raises:**
An errno-specific subclass of
Errorreflecting the errno from the caughtOSError.
**Example:**
import os # Wrap os.remove to raise errno-specific exceptions try: checked_call(os.remove, "nonexistentfile.txt") except ENOENT as e: print(f"Caught error: {e}")
Function: __getattr__(attr: str) -> type[Error]
Module-level magic function to enable lazy retrieval of errno exception classes by attribute name on the module itself.
**Example:**
from error import ENOENT
try:
raise ENOENT("File does not exist")
except ENOENT as e:
print(e)
This function internally delegates to the singleton `_error_maker` instance.
Important Implementation Details
Lazy Initialization: Error classes for each errno are created only when first accessed, reducing upfront overhead.
Windows Error Mapping: Because Windows uses different error codes,
_winerrnomapmaps Windows error numbers to POSIX errno equivalents to unify error handling.Dynamic Class Creation: Uses
type()to dynamically create new exception classes with appropriate names and docstrings fetched fromos.strerror.Typing: Uses typing generics and
ParamSpecfor type-safe function wrappers.Exception Wrapping: The
checked_callmethod wraps arbitrary functions and converts their raisedOSErrorinto an errno-specific exception for clearer error handling in client code.
Interaction with Other Parts of the System
This module is designed to be imported where OS or IO calls are made, providing a consistent and detailed error handling approach.
The
checked_callfunction can be used as a wrapper around any function that may raise OS-level errors to automatically raise errno-specific exceptions.Dynamically generated error classes can be imported and caught explicitly in exception handling blocks, improving readability and maintainability.
The module depends on standard Python modules:
errno,os, andsys.It fits into larger systems that require robust error classification and handling for filesystem and OS interactions.
Usage Example
from error import checked_call, ENOENT
def delete_file(path):
# This will raise ENOENT if file does not exist
checked_call(os.remove, path)
try:
delete_file("missing.txt")
except ENOENT as e:
print(f"File not found: {e}")
Diagram
classDiagram
class Error {
+__repr__() str
+__str__() str
}
class ErrorMaker {
-_errno2class: dict[int, type[Error]]
+__getattr__(name: str) type[Error]
-_geterrnoclass(eno: int) type[Error]
+checked_call(func: Callable, *args, **kwargs) R
}
ErrorMaker --> Error : subclasses
Summary
The [error.py](/projects/286/67543) module provides a dynamic, lazy-loading system for creating and raising errno-specific exceptions, improving error clarity for OS and IO operations. It wraps system calls to raise meaningful exceptions tied directly to the POSIX error codes, facilitating more precise error handling in applications dealing with file and OS level operations.