Coverage for an_website/utils/emoji.py: 91.667%
24 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-24 18:26 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-24 18:26 +0000
1# This program is free software: you can redistribute it and/or modify
2# it under the terms of the GNU Affero General Public License as
3# published by the Free Software Foundation, either version 3 of the
4# License, or (at your option) any later version.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU Affero General Public License for more details.
10#
11# You should have received a copy of the GNU Affero General Public License
12# along with this program. If not, see <https://www.gnu.org/licenses/>.
14"""Utilities for dealing with emojis."""
16from collections.abc import Iterable
17from typing import TypeGuard
19from emoji import EmojiMatch, Token, analyze
20from emoji.tokenizer import tokenize
23def _is_emoji_token(token: Token) -> TypeGuard[Token]:
24 """Check if the token represents an emoji."""
25 return isinstance(token.value, EmojiMatch)
28def split_text_into_emoji_and_non_emoji_parts(
29 text: str,
30) -> Iterable[tuple[str, bool]]:
31 """Return tuple of strings and is_emoji bools."""
32 it = iter(analyze(text, non_emoji=True, join_emoji=True))
34 try:
35 first = next(it)
36 except StopIteration:
37 return
39 chars = [first.chars]
40 is_emoji = _is_emoji_token(first)
42 for value in it:
43 if is_emoji != _is_emoji_token(value):
44 yield ("".join(chars), is_emoji)
45 chars.clear()
46 is_emoji = not is_emoji
48 chars.append(value.chars)
50 if chars:
51 yield ("".join(chars), is_emoji)
54def text_contains_emoji(text: str) -> bool:
55 """Check if the given string contains at-least one emoji."""
56 # pylint: disable-next=bad-builtin
57 return any(filter(_is_emoji_token, tokenize(text, False)))