Source code for facelift.magic

# -*- encoding: utf-8 -*-
# Copyright (c) 2020 Stephen Bunn <stephen@bunn.io>
# ISC License <https://opensource.org/licenses/isc>

"""Contains helpers and enums used to guess the type of media that is being processed.

This module utilizes `python-magic <https://github.com/ahupp/python-magic>`_ which
in turn uses `libmagic <https://linux.die.net/man/3/libmagic>`_ to guess the appropriate
mimetype of some byte buffer.

Attributes:
    DEFAULT_MAGIC_BUFFER_SIZE (int): The default number of bytes to try and read from
        when making a guess at the mimetype of some file.
"""

from pathlib import Path
from typing import Optional

from .types import MediaType

try:
    import magic
except ImportError as exc:  # pragma: no cover
    raise ImportError(
        "libmagic binary not found, please install all necessary system requirements "
        "documented at https://bit.ly/3hJ6IGI"
    ) from exc


DEFAULT_MAGIC_BUFFER_SIZE = 2 ** 11


[docs]def get_mimetype( media_filepath: Path, buffer_size: Optional[int] = None ) -> Optional[str]: """Try and determine the mimetype for content at the given filepath. Args: media_filepath (~pathlib.Path): The filepath to guess the mimetype of buffer_size (Optional[int], optional): The number of bytes to use for guessing the mimetype of the given file. Defaults to the value of :attr:`~DEFAULT_MAGIC_BUFFER_SIZE`. Raises: FileNotFoundError: When the provided filepath does not exist Returns: Optional[str]: The guessed mimetype if a guess can be safely made """ if not media_filepath.is_file(): raise FileNotFoundError(f"no such file {media_filepath!s} exists") with media_filepath.open("rb") as media_buffer: return magic.from_buffer( media_buffer.read(buffer_size or DEFAULT_MAGIC_BUFFER_SIZE), mime=True )
[docs]def get_media_type( media_filepath: Path, buffer_size: Optional[int] = None, validate: bool = False ) -> Optional[MediaType]: """Try and determine the media type for content at the given filepath. Args: media_filepath (~pathlib.Path): The filepath to guess the media type of buffer_size (Optional[int], optional): The number of bytes to use for guessing the media type of the given file. Defaults to the value of :attr:`~DEFAULT_MAGIC_BUFFER_SIZE`. validate (bool, optional): If truthy, a :class:`ValueError` will be raised if the given file's mimetype does not match a supported :class:`~.types.MediaType`. Defaults to False. Raises: FileNotFoundError: When the provided filepath does not exist ValueError: When ``validate`` is truthy and the given filepath does not match a supported :class:`~.types.MediaType` Returns: Optional[~.types.MediaType]: The appropriate media type enum attribute for the given filepath, if a successful guess and media type match is made """ mimetype = get_mimetype(media_filepath, buffer_size=buffer_size) if not mimetype: return None mime_prefix, *_ = mimetype.lower().split("/") try: return MediaType(mime_prefix) except ValueError as exc: if not validate: return None raise ValueError( f"unhandled media type for media at {media_filepath!s} " f"(mimetype: {mimetype!s})" ) from exc