--- /dev/null
+from functools import partial
+
+
+def find_entrypoints(group_name: str):
+ """
+ Find entrypoints of a given group using either `importlib.metadata` or the
+ older `pkg_resources` mechanism.
+
+ Yields tuples of the entrypoint name and a callable function that will
+ load the actual entrypoint.
+ """
+ try:
+ from importlib.metadata import entry_points
+ except ImportError:
+ pass
+ else:
+ eps = entry_points()
+ if isinstance(eps, dict): # Old structure before Python 3.10
+ group_eps = eps.get(group_name, [])
+ else: # New structure in Python 3.10+
+ group_eps = (ep for ep in eps if ep.group == group_name)
+ for entry_point in group_eps:
+ yield (entry_point.name, entry_point.load)
+ return
+
+ try:
+ from pkg_resources import working_set
+ except ImportError:
+ pass
+ else:
+ for entry_point in working_set.iter_entry_points(group_name):
+ yield (entry_point.name, partial(entry_point.load, require=True))
def _find_checkers() -> list[Callable[[Catalog | None, Message], object]]:
+ from babel.messages._compat import find_entrypoints
checkers: list[Callable[[Catalog | None, Message], object]] = []
- try:
- from pkg_resources import working_set
- except ImportError:
- pass
- else:
- for entry_point in working_set.iter_entry_points('babel.checkers'):
- checkers.append(entry_point.load())
+ checkers.extend(load() for (name, load) in find_entrypoints('babel.checkers'))
if len(checkers) == 0:
- # if pkg_resources is not available or no usable egg-info was found
+ # if entrypoints are not available or no usable egg-info was found
# (see #230), just resort to hard-coded checkers
return [num_plurals, python_format]
return checkers
Mapping,
MutableSequence,
)
+from functools import lru_cache
from os.path import relpath
from textwrap import dedent
from tokenize import COMMENT, NAME, OP, STRING, generate_tokens
from typing import TYPE_CHECKING, Any
+from babel.messages._compat import find_entrypoints
from babel.util import parse_encoding, parse_future_flags, pathmatch
if TYPE_CHECKING:
return lineno, translatable, comments, context
+@lru_cache(maxsize=None)
+def _find_extractor(name: str):
+ for ep_name, load in find_entrypoints(GROUP_NAME):
+ if ep_name == name:
+ return load()
+ return None
+
+
def extract(
method: _ExtractionMethod,
fileobj: _FileObj,
module, attrname = method.split(':', 1)
func = getattr(__import__(module, {}, {}, [attrname]), attrname)
else:
- try:
- from pkg_resources import working_set
- except ImportError:
- pass
- else:
- for entry_point in working_set.iter_entry_points(GROUP_NAME,
- method):
- func = entry_point.load(require=True)
- break
+ func = _find_extractor(method)
if func is None:
- # if pkg_resources is not available or no usable egg-info was found
- # (see #230), we resort to looking up the builtin extractors
- # directly
- builtin = {
- 'ignore': extract_nothing,
- 'python': extract_python,
- 'javascript': extract_javascript,
- }
- func = builtin.get(method)
+ # if no named entry point was found,
+ # we resort to looking up a builtin extractor
+ func = _BUILTIN_EXTRACTORS.get(method)
if func is None:
raise ValueError(f"Unknown extraction method {method!r}")
lineno += len(line_re.findall(expression_contents))
expression_contents = ''
prev_character = character
+
+
+_BUILTIN_EXTRACTORS = {
+ 'ignore': extract_nothing,
+ 'python': extract_python,
+ 'javascript': extract_javascript,
+}