Source code for gravify.avatars.generator

"""Avatar URL generator for Gravify."""

from typing import cast
from urllib.parse import urlencode

from gravify.avatars.exceptions import (
    InitialsAndNameError,
    InitialsDefaultImageNotSetError,
)
from gravify.avatars.options import DefaultImage, Rating
from gravify.utils import hash_email

_DEFAULT_AVATAR_SIZE = 80
_DEFAULT_RATING = Rating.G


[docs] class AvatarGenerator: """Gravatar avatar URL generator."""
[docs] def __init__( # noqa: PLR0913 self, size: int | None = None, *, default_image: str | DefaultImage | None = None, force_default: bool | None = False, rating: Rating | None = None, initials: str | None = None, name: str | None = None, ) -> None: """Initialize the avatar generator with reusable options. Args: size: Side length of the square avatar in pixels (default is 80). default_image: Default image type if no avatar is found (default is the Gravatar logo). force_default: Force the default image to always return (default is False). rating: Rating of the avatar (default is G). initials: Initials to use for the avatar if no image is found. name: Name to use for the avatar initials if no image is found. Raises: InitialsAndNameError: If both initials and name are provided. """ self.size = size self.default_image = default_image self.force_default = force_default self.rating = rating if initials is not None and name is not None: raise InitialsAndNameError self.initials = initials self.name = name
@property def initials(self) -> str | None: """Get the initials used for the "initials" default avatar.""" return self._initials @initials.setter def initials(self, value: str | None) -> None: """Set the initials used for the "initials" default avatar. Raises: InitialsDefaultImageNotSetError: If initials are set but the default image is not set to INITIALS. """ if value is not None and self.default_image != DefaultImage.INITIALS: raise InitialsDefaultImageNotSetError self._initials: str | None = value self._name: str | None = None @property def name(self) -> str | None: """Get the name used for the "initials" default avatar.""" return self._name @name.setter def name(self, value: str | None) -> None: """Set the name used for the "initials" default avatar. Raises: InitialsDefaultImageNotSetError: If a name is set but the default image is not set to INITIALS. """ if value is not None and self.default_image != DefaultImage.INITIALS: raise InitialsDefaultImageNotSetError self._name = value self._initials = None def _generate_parameters(self) -> dict[str, str | int]: """Generate the parameters for the avatar URL. This method will not include parameters that are set to their default values, as defined by the Gravatar API specifications. Returns: A dictionary of parameters to be included in the avatar URL query string. """ params: dict[str, str | int] = {} if self.size is not None and self.size != _DEFAULT_AVATAR_SIZE: params['s'] = self.size if self.default_image is not None: params['d'] = ( self.default_image.value if isinstance(self.default_image, DefaultImage) else self.default_image ) if self.force_default: params['f'] = 'y' if self.rating is not None and self.rating != _DEFAULT_RATING: params['r'] = cast('str', self.rating.value) # type: ignore[redundant-cast] if self.initials is not None: params['initials'] = self.initials if self.name is not None: params['name'] = self.name return params
[docs] def generate_url(self, email: str) -> str: """Generate the avatar URL for the given email. Args: email: The email address to generate the avatar for. Returns: The generated avatar URL. """ email_hash = hash_email(email) url = f'https://gravatar.com/avatar/{email_hash}' if query_string := urlencode(self._generate_parameters()): url += f'?{query_string}' return url