import sys
import importlib.resources
import json
from functools import lru_cache
from warnings import warn
from typing import Any, BinaryIO, Dict, List, Optional
from emoji.unicode_codes.data_dict import STATUS, LANGUAGES
__all__ = [
'get_emoji_by_name',
'load_from_json',
'EMOJI_DATA',
'STATUS',
'LANGUAGES',
]
_DEFAULT_KEYS = ('en', 'alias', 'E', 'status') # The keys in emoji.json
_loaded_keys: List[str] = list(
_DEFAULT_KEYS
) # Keep track of keys already loaded from json files to avoid loading them twice
@lru_cache(maxsize=4000)
def get_emoji_by_name(name: str, language: str) -> Optional[str]:
"""
Find emoji by short-name in a specific language.
Returns None if not found
:param name: emoji short code e.g. ":banana:"
:param language: language-code e.g. 'es', 'de', etc. or 'alias'
"""
fully_qualified = STATUS['fully_qualified']
if language == 'alias':
for emj, data in EMOJI_DATA.items():
if name in data.get('alias', []) and data['status'] <= fully_qualified:
return emj
language = 'en'
for emj, data in EMOJI_DATA.items():
if data.get(language) == name and data['status'] <= fully_qualified:
return emj
return None
class EmojiDataDict(Dict[str, Any]):
"""Replaces built-in-dict in the values of the EMOJI_DATA dict.
Auto loads language data when accessing language data via
key-access without prior loading of the language:
e.g. EMOJI_DATA['👌']['fr'] will auto load French language and not throw
a KeyError.
Shows a deprecation warning explainging that `emoji.config.load_language()`
should be used."""
def __missing__(self, key: str) -> str:
"""Auto load language `key`, raises KeyError if language is no supported."""
if key in LANGUAGES and key not in _loaded_keys:
load_from_json(key)
if key in self:
warn(
f"""Use emoji.config.load_language('{key}') before accesing EMOJI_DATA[emj]['{key}'].
Accessing EMOJI_DATA[emj]['{key}'] without loading the language is deprecated.""",
DeprecationWarning,
stacklevel=3,
)
return self[key] # type: ignore
raise KeyError(key)
EMOJI_DATA: Dict[str, Dict[str, Any]]
def _open_file(name: str) -> BinaryIO:
if sys.version_info >= (3, 9):
return importlib.resources.files('emoji.unicode_codes').joinpath(name).open('rb')
else:
return importlib.resources.open_binary('emoji.unicode_codes', name)
def _load_default_from_json():
global EMOJI_DATA
global _loaded_keys
with _open_file('emoji.json') as f:
EMOJI_DATA = dict(json.load(f, object_pairs_hook=EmojiDataDict)) # type: ignore
_loaded_keys = list(_DEFAULT_KEYS)
def load_from_json(key: str):
"""Load values from the file 'emoji_{key}.json' into EMOJI_DATA"""
if key in _loaded_keys:
return
if key not in LANGUAGES:
raise NotImplementedError('Language not supported', key)
with _open_file(f'emoji_{key}.json') as f:
for emj, value in json.load(f).items():
EMOJI_DATA[emj][key] = value # type: ignore
_loaded_keys.append(key)
_load_default_from_json()