Source code for f_lib.archive_extractor._archive_extractor
"""Abstract base class for archive extractors."""
from __future__ import annotations
from abc import ABC, abstractmethod
from pathlib import Path
from typing import ClassVar, Literal
from .exceptions import ArchiveTypeError
[docs]
class ArchiveExtractor(ABC):
"""Abstract base class for archive extractors."""
SUFFIX: ClassVar[tuple[str, ...]] = ()
"""File extension/suffix supported by the extractor."""
archive: Path
"""Resolved path to the archive file."""
[docs]
def __init__(self, archive: Path | str, *, strict: bool = True) -> None:
"""Instantiate class.
Args:
archive: Path to the archive file.
strict: Raise an error if the provided archive file does not have the
expected file extension/suffix.
"""
self.archive = Path(archive).resolve()
if not self.archive.is_file():
raise FileNotFoundError(self.archive)
if strict and self.SUFFIX and not self.can_extract(self.archive):
raise ArchiveTypeError(self.archive, self.SUFFIX)
[docs]
@abstractmethod
def extract(self, destination: Path) -> Path:
"""Extract the archive file.
Args:
destination: Where the archive file will be extracted to.
Returns:
Path to the extraction.
"""
[docs]
@classmethod
def can_extract(cls, archive: Path | str) -> bool:
"""Determine if the extractor can attempt to extract the file.
Args:
archive: Path to an archive file.
"""
path = Path(archive) # ensure it's a path object
if not path.is_file():
return False
return any(True for suffix in cls.SUFFIX if "".join(path.suffixes).endswith(suffix))
def __bool__(self) -> Literal[True]:
return True
def __str__(self) -> str:
return str(self.archive)