Kumi
e82ccb2701
- Extended copyright to reflect the current year. - Incremented project version to indicate new features and fixes. - Added a new script entry for easier execution, increasing utility and accessibility. - Updated project URLs for better alignment with current infrastructure. - Refactored settings path for simplicity and consistency across deployments. - Improved code readability and maintenance across several modules by cleaning up redundant code, adding missing type annotations, and ensuring consistent code formatting. - Enhanced logging capabilities and error handling to improve diagnostics and troubleshooting, supporting more robust error recovery mechanisms. - Implemented more graceful handling of termination signals to ensure clean shutdown and resource cleanup, enhancing the robustness of the application in production environments. - Introduced command-line argument parsing for configuration file path customization, improving flexibility in different runtime environments. These changes collectively improve the project's maintainability, reliability, and user experience, laying a stronger foundation for future development.
104 lines
3.3 KiB
Python
104 lines
3.3 KiB
Python
from .chunk import Chunk
|
|
from .database import Database
|
|
|
|
from typing import Optional
|
|
|
|
import hashlib
|
|
import os.path
|
|
|
|
|
|
class File:
|
|
"""Object representing a file found in a local Directory"""
|
|
|
|
def __init__(
|
|
self, name: str, directory, uuid: Optional[str] = None, dbclass: type = Database
|
|
) -> None:
|
|
"""Initialize new File object
|
|
|
|
Args:
|
|
name (str): Filename (basename without path) of the File to create
|
|
directory (classes.directory.Directory): Directory object the File
|
|
is located within
|
|
uuid (str, optional): Unique identifier of this File object. Will
|
|
be retrieved from database if None. Defaults to None.
|
|
dbclass (type): Class to use for database connections. Defaults to
|
|
built-in Database using sqlite3.
|
|
|
|
Raises:
|
|
FileNotFoundError: Raised if the specified File does not exist
|
|
"""
|
|
self.name = name
|
|
self.directory = directory
|
|
self.dbclass = dbclass
|
|
|
|
if not self.exists():
|
|
raise FileNotFoundError(
|
|
f"File {self.name} does not exist in {self.directory.name}!"
|
|
)
|
|
|
|
self.uuid = uuid or self.getUUID()
|
|
|
|
def exists(self) -> bool:
|
|
"""Check if the File exists on the local file system
|
|
|
|
Returns:
|
|
bool: True if the File exists, else False
|
|
"""
|
|
return os.path.isfile(self.directory.location / self.name)
|
|
|
|
def moveCompleted(self) -> None:
|
|
self.getFullPath().rename(self.directory.completeddir / self.name)
|
|
|
|
def getUUID(self) -> str:
|
|
"""Return unique identifier for this File object
|
|
|
|
Returns:
|
|
str: File object's UUID retrieved from database
|
|
"""
|
|
db = self.dbclass()
|
|
return db.getFileUUID(self)
|
|
|
|
def getFullPath(self) -> str:
|
|
"""Get the full path of the File
|
|
|
|
Returns:
|
|
str: Full path of the File on the local file system
|
|
"""
|
|
return self.directory.location / self.name
|
|
|
|
def getHash(self) -> str:
|
|
"""Get hash for this File
|
|
|
|
Returns:
|
|
str: SHA256 for the full content of this File
|
|
"""
|
|
return self.getChunk(-1).getHash()
|
|
|
|
def getChunk(self, count: int, size: Optional[int] = None) -> Chunk:
|
|
"""Get a Chunk of this File
|
|
|
|
Args:
|
|
count (int): Position of the Chunk in a list of equally large
|
|
Chunks (first index: 0). -1 represents a Chunk containing the
|
|
complete file.
|
|
size (int, optional): Size of the Chunk to create in Bytes. Must
|
|
be set if count is not -1. Defaults to None.
|
|
|
|
Returns:
|
|
classes.chunk.Chunk: Chunk object containing File content from
|
|
(count * size) bytes to ((count + 1) * size - 1) bytes
|
|
|
|
Raises:
|
|
ValueError: Raised if size is not set for a count that is not -1
|
|
"""
|
|
if count != -1 and not size:
|
|
raise ValueError(
|
|
"A Chunk size needs to be passed to getChunk() if not using the complete file (-1)!"
|
|
)
|
|
|
|
with open(self.getFullPath(), "rb") as binary:
|
|
binary.seek((count * size) if count > 0 else 0)
|
|
data = binary.read(size if count >= 0 else None)
|
|
|
|
return Chunk(self, count, data)
|