Source code for bethesda_structs._common

# Copyright (c) 2018 Stephen Bunn <stephen@bunn.io>
# MIT License <https://choosealicense.com/licenses/mit/>

import io
import os
import abc
from typing import TypeVar

T_BaseFiletype = TypeVar("BaseFiletype")


[docs]class BaseFiletype(abc.ABC): """The base filetype for all supported file parsers. """
[docs] @abc.abstractclassmethod def can_handle(cls, filepath: str) -> bool: """Determines if a given `filepath` can be handled by the archive. Args: filepath (str): The filepath to evaluate Raises: NotImplementedError: Subclasses must implement """ raise NotImplementedError
[docs] @abc.abstractclassmethod def parse(cls, content: bytes, filepath: str = None) -> T_BaseFiletype: """Create a :class:`BaseFiletype` from a byte array. Args: content (bytes): The byte content filepath (str, optional): Defaults to None. Sets the filepath attribute for user's reference Raises: NotImplementedError: Subclasses must implement Returns: :class:`BaseFiletype`: A filetype instance """ raise NotImplementedError
[docs] @classmethod def parse_stream( cls, stream: io.BufferedReader, filepath: str = None ) -> T_BaseFiletype: """Create a :class:`BaseFiletype` from a file stream. Args: stream (io.BufferedReader): A file stream to read from. filepath (str, optional): Defaults to None. Sets the filepath attribute for user's reference. Raises: ValueError: If the given stream is not of ``bytes`` Returns: :class:`BaseFiletype`: A filetype instance """ if not isinstance(stream.peek(1), bytes): raise ValueError( f"stream {stream!r} is not a stream of bytes, recieved {type(stream)!r}" ) return cls.parse(stream.read(), filepath=filepath)
[docs] @classmethod def parse_file(cls, filepath: str) -> T_BaseFiletype: """Create a :class:`BaseFiletype` from a given filepath. Args: filepath (str): The filepath to read from Raises: FileNotFoundError: If the given filepath does not exist Returns: :class:`BaseFiletype`: A filetype instance """ if not os.path.isfile(filepath): raise FileNotFoundError(f"no such file {filepath!r} exists") with open(filepath, "rb") as stream: return cls.parse_stream(stream, filepath)