codekingpro/portable-devtools
114k
1from __future__ import annotations2 3import importlib.metadata as importlib_metadata4import os5import warnings6from collections.abc import Iterable7from typing import TYPE_CHECKING, Final8 9if TYPE_CHECKING:10 from . import PydanticPluginProtocol11 12 13PYDANTIC_ENTRY_POINT_GROUP: Final[str] = 'pydantic'14 15# cache of plugins16_plugins: dict[str, PydanticPluginProtocol] | None = None17# return no plugins while loading plugins to avoid recursion and errors while importing plugins18# this means that if plugins use pydantic19_loading_plugins: bool = False20 21 22def get_plugins() -> Iterable[PydanticPluginProtocol]:23 """Load plugins for Pydantic.24 25 Inspired by: https://github.com/pytest-dev/pluggy/blob/1.3.0/src/pluggy/_manager.py#L376-L40226 """27 disabled_plugins = os.getenv('PYDANTIC_DISABLE_PLUGINS')28 global _plugins, _loading_plugins29 if _loading_plugins:30 # this happens when plugins themselves use pydantic, we return no plugins31 return ()32 elif disabled_plugins in ('__all__', '1', 'true'):33 return ()34 elif _plugins is None:35 _plugins = {}36 # set _loading_plugins so any plugins that use pydantic don't themselves use plugins37 _loading_plugins = True38 try:39 for dist in importlib_metadata.distributions():40 for entry_point in dist.entry_points:41 if entry_point.group != PYDANTIC_ENTRY_POINT_GROUP:42 continue43 if entry_point.value in _plugins:44 continue45 if disabled_plugins is not None and entry_point.name in disabled_plugins.split(','):46 continue47 try:48 _plugins[entry_point.value] = entry_point.load()49 except (ImportError, AttributeError) as e:50 warnings.warn(51 f'{e.__class__.__name__} while loading the `{entry_point.name}` Pydantic plugin, '52 f'this plugin will not be installed.\n\n{e!r}',53 stacklevel=2,54 )55 finally:56 _loading_plugins = False57 58 return _plugins.values()59 