Skip to content

Instantly share code, notes, and snippets.

@sarmadgulzar
Last active July 4, 2024 20:07
Show Gist options
  • Save sarmadgulzar/1d9b96b01b180b0f8e0b7f5e93890d7d to your computer and use it in GitHub Desktop.
Save sarmadgulzar/1d9b96b01b180b0f8e0b7f5e93890d7d to your computer and use it in GitHub Desktop.
A file helper that can create, read, update, delete & rename files.
import logging
import os
from pathlib import Path
class FileOperationError(Exception):
"""Custom exception for file operations."""
class FileHelper:
"""
A utility class for performing various file operations.
This class provides methods for creating, reading, updating, renaming,
and deleting files. It uses logging for operation tracking and
implements robust error handling.
Attributes:
logger (logging.Logger): Logger instance for the class.
"""
def __init__(self, log_level: int = logging.INFO):
"""
Initialize the FileHelper with a configured logger.
Args:
log_level (int): The logging level to use. Defaults to logging.INFO.
"""
self.logger = self._setup_logger(log_level)
@staticmethod
def _setup_logger(log_level: int) -> logging.Logger:
"""
Set up and configure the logger.
Args:
log_level (int): The logging level to use.
Returns:
logging.Logger: Configured logger instance.
"""
logger = logging.getLogger(__name__)
logger.setLevel(log_level)
if not logger.handlers:
handler = logging.StreamHandler()
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def create(self, filename: str, content: str = "") -> None:
"""
Create a new file with optional content.
Args:
filename (str): The name of the file to create.
content (str, optional): The initial content of the file. Defaults to an empty string.
Raises:
FileOperationError: If there's an error creating the file.
"""
try:
with open(filename, "w") as file:
file.write(content)
self.logger.info(f"File '{filename}' created successfully.")
except IOError as e:
self.logger.error(f"Error creating file '{filename}': {str(e)}")
raise FileOperationError(f"Failed to create file '{filename}'") from e
def read(self, filename: str) -> str | None:
"""
Read and return the contents of a file.
Args:
filename (str): The name of the file to read.
Returns:
str | None: The contents of the file, or None if the file doesn't exist.
Raises:
FileOperationError: If there's an error reading the file.
"""
try:
with open(filename, "r") as file:
content = file.read()
self.logger.info(f"File '{filename}' read successfully.")
return content
except FileNotFoundError:
self.logger.warning(f"File '{filename}' not found.")
return None
except IOError as e:
self.logger.error(f"Error reading file '{filename}': {str(e)}")
raise FileOperationError(f"Failed to read file '{filename}'") from e
def update(self, filename: str, new_content: str) -> None:
"""
Update the entire contents of a file.
Args:
filename (str): The name of the file to update.
new_content (str): The new content to write to the file.
Raises:
FileOperationError: If there's an error updating the file.
"""
try:
with open(filename, "w") as file:
file.write(new_content)
self.logger.info(f"File '{filename}' updated successfully.")
except IOError as e:
self.logger.error(f"Error updating file '{filename}': {str(e)}")
raise FileOperationError(f"Failed to update file '{filename}'") from e
def rename(self, old_name: str, new_name: str) -> None:
"""
Rename a file.
Args:
old_name (str): The current name of the file.
new_name (str): The new name for the file.
Raises:
FileOperationError: If there's an error renaming the file.
"""
try:
os.rename(old_name, new_name)
self.logger.info(
f"File renamed from '{old_name}' to '{new_name}' successfully."
)
except FileNotFoundError:
self.logger.error(f"File '{old_name}' not found.")
raise FileOperationError(f"File '{old_name}' not found") from None
except FileExistsError:
self.logger.error(f"File '{new_name}' already exists.")
raise FileOperationError(f"File '{new_name}' already exists") from None
except OSError as e:
self.logger.error(
f"Error renaming file from '{old_name}' to '{new_name}': {str(e)}"
)
raise FileOperationError(f"Failed to rename file '{old_name}'") from e
def delete(self, filename: str) -> None:
"""
Delete a file.
Args:
filename (str): The name of the file to delete.
Raises:
FileOperationError: If there's an error deleting the file.
"""
try:
os.remove(filename)
self.logger.info(f"File '{filename}' deleted successfully.")
except FileNotFoundError:
self.logger.warning(f"File '{filename}' not found.")
except OSError as e:
self.logger.error(f"Error deleting file '{filename}': {str(e)}")
raise FileOperationError(f"Failed to delete file '{filename}'") from e
@staticmethod
def get_file_info(filename: str) -> dict:
"""
Get information about a file.
Args:
filename (str): The name of the file.
Returns:
dict: A dictionary containing file information (size, creation time, modification time).
Raises:
FileOperationError: If there's an error getting file information.
"""
try:
file_path = Path(filename)
stats = file_path.stat()
return {
"size": stats.st_size,
"created": stats.st_ctime,
"modified": stats.st_mtime,
}
except FileNotFoundError:
raise FileOperationError(f"File '{filename}' not found")
except OSError as e:
raise FileOperationError(f"Failed to get info for file '{filename}'") from e
# Example usage
if __name__ == "__main__":
helper = FileHelper(log_level=logging.DEBUG)
try:
helper.create("example.txt", "Hello, World!")
content = helper.read("example.txt")
print("File contents:", content)
helper.update("example.txt", "Updated content")
helper.rename("example.txt", "new_example.txt")
file_info = FileHelper.get_file_info("new_example.txt")
print("File info:", file_info)
helper.delete("new_example.txt")
except FileOperationError as e:
print(f"An error occurred: {str(e)}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment