Source code for glasses_detector.utils

"""
.. class:: FilePath

.. data:: FilePath
    :noindex:
    :type: typing.TypeAliasType
    :value: str | bytes | os.PathLike

    Type alias for a file path.

        :class:`str` | :class:`bytes` | :class:`os.PathLike`
"""

import functools
import imghdr
import os
import typing
from typing import Any, Callable, Iterable, TypeGuard, overload
from urllib.parse import urlparse

import torch

type FilePath = str | bytes | os.PathLike


class copy_signature[**P, T]:
    """Decorator to copy a function's or a method's signature.

    This decorator takes a callable and copies its signature to the
    decorated function or method.

    Example
    -------

    .. code-block:: python

        def full_signature(x: bool, *extra: int) -> str: ...

        @copy_signature(full_signature)
        def test_signature(*args, **kwargs):
            return full_signature(*args, **kwargs)

        reveal_type(test_signature)  # 'def (x: bool, *extra: int) -> str'

    .. seealso::

        https://github.com/python/typing/issues/270#issuecomment-1344537820

    Args:
        source (typing.Callable[P, T]): The callable whose signature to
            copy.
    """

    def __init__(self, source: Callable[P, T]):
        # The source callable
        self.source = source

    def __call__(self, target: Callable[..., T]) -> Callable[P, T]:
        @functools.wraps(self.source)
        def wrapped(*args: P.args, **kwargs: P.kwargs) -> T:
            return target(*args, **kwargs)

        return wrapped


[docs] class eval_infer_mode: """Context manager and decorator for evaluation and inference. This class can be used as a context manager or a decorator to set a PyTorch :class:`~torch.nn.Module` to evaluation mode via :meth:`~torch.nn.Module.eval` and enable :class:`~torch.inference_mode` for the duration of a function or a ``with`` statement. After the function or the ``with`` statement, the model's mode, i.e., :attr:`~torch.nn.Module.training` property, and :class:`~torch.inference_mode` are restored to their original states. Example ------- .. code-block:: python model = ... # Your PyTorch model @eval_infer_mode(model) def your_function(): # E.g., forward pass pass # or with eval_infer_mode(model): # E.g., forward pass pass Args: model (torch.nn.Module): The PyTorch model to be set to evaluation mode. """ def __init__(self, model: torch.nn.Module): self.model = model self.was_training = model.training def __call__[F](self, func: F) -> F: @functools.wraps(func) def wrapper(*args, **kwargs): with self: return func(*args, **kwargs) return wrapper def __enter__(self): self.model.eval() self._inference_mode = torch.inference_mode(True) self._inference_mode.__enter__() def __exit__(self, type: Any, value: Any, traceback: Any): self._inference_mode.__exit__(type, value, traceback) self.model.train(self.was_training)
[docs] def is_url(x: str) -> bool: """Check if a string is a valid URL. Takes any string and checks if it is a valid URL. .. seealso:: https://stackoverflow.com/a/38020041 Args: x: The string to check. Returns: :data:`True` if the string is a valid URL, :data:`False` otherwise. """ try: result = urlparse(x) return all([result.scheme, result.netloc]) except: return False
@overload def flatten[T](items: T) -> T: ... @overload def flatten[T](items: typing.Iterable[T | typing.Iterable]) -> list[T]: ...
[docs] def flatten[T](items: T | Iterable[T | Iterable]) -> T | list[T]: """Flatten a nested list. This function takes any nested iterable and returns a flat list. Args: items (T | typing.Iterable[T | typing.Iterable]): The nested iterable to flatten. Returns: T | list[T]: The flattened list or the original ``items`` value if it is not an iterable or is of type :class:`str`. """ if not isinstance(items, Iterable) or isinstance(items, str): # Not iterable return items # Init flat list flattened = [] for item in items: if isinstance(item, Iterable) and not isinstance(item, str): flattened.extend(flatten(item)) else: flattened.append(item) return flattened
[docs] def is_path_type(path: Any) -> TypeGuard[FilePath]: """Check if an object is a valid path type. This function takes any object and checks if it is a valid path type. A valid path type is either a :class:`str`, :class:`bytes` or :class:`os.PathLike` object. Args: path: The object to check. Returns: :data:`True` if the object is a valid path type, :data:`False` otherwise. """ return isinstance(path, (str, bytes, os.PathLike))
[docs] def is_image_file(path: FilePath) -> bool: """Check if a file is an image. This function takes a file path and checks if it is an image file. This is done by checking if the file exists and if it has a valid image extension. Args: path: The path to the file. Returns: :data:`True` if the file is an image, :data:`False` otherwise. """ return os.path.isfile(path) and imghdr.what(path) is not None