mirror of
https://github.com/mkdocs/mkdocs.git
synced 2026-03-27 09:58:31 +07:00
Replace pkg_resources with importlib_metadata
This is using the new "selection interface" ( by calling `entry_points` with the `group` parameter) that is being introduced in `importlib.metadata` of Python 3.10 (currently in alpha). While the backport (`importlib_metadata`) introduced the same change in version 3.6, various improvements have been made up through the current release (3.10). Therefore we require `importlib_metadata>=3.10` for all supported versions of Python (3.6-3.9).
This commit is contained in:
@@ -4,8 +4,8 @@ Implements the plugin API for MkDocs.
|
||||
"""
|
||||
|
||||
|
||||
import pkg_resources
|
||||
import logging
|
||||
import importlib_metadata
|
||||
from collections import OrderedDict
|
||||
|
||||
from mkdocs.config.base import Config
|
||||
@@ -22,9 +22,9 @@ EVENTS = (
|
||||
|
||||
|
||||
def get_plugins():
|
||||
""" Return a dict of all installed Plugins by name. """
|
||||
""" Return a dict of all installed Plugins as {name: EntryPoint}. """
|
||||
|
||||
plugins = pkg_resources.iter_entry_points(group='mkdocs.plugins')
|
||||
plugins = importlib_metadata.entry_points(group='mkdocs.plugins')
|
||||
|
||||
return {plugin.name: plugin for plugin in plugins}
|
||||
|
||||
|
||||
@@ -210,7 +210,7 @@ MockEntryPoint = mock.Mock()
|
||||
MockEntryPoint.configure_mock(**{'name': 'sample', 'load.return_value': DummyPlugin})
|
||||
|
||||
|
||||
@mock.patch('pkg_resources.iter_entry_points', return_value=[MockEntryPoint])
|
||||
@mock.patch('importlib_metadata.entry_points', return_value=[MockEntryPoint])
|
||||
class TestPluginConfig(unittest.TestCase):
|
||||
|
||||
def test_plugin_config_without_options(self, mock_class):
|
||||
|
||||
@@ -251,17 +251,17 @@ class UtilsTests(unittest.TestCase):
|
||||
sorted(utils.get_theme_names()),
|
||||
['mkdocs', 'readthedocs'])
|
||||
|
||||
@mock.patch('pkg_resources.iter_entry_points', autospec=True)
|
||||
@mock.patch('importlib_metadata.entry_points', autospec=True)
|
||||
def test_get_theme_dir(self, mock_iter):
|
||||
|
||||
path = 'some/path'
|
||||
|
||||
theme = mock.Mock()
|
||||
theme.name = 'mkdocs2'
|
||||
theme.dist.key = 'mkdocs2'
|
||||
theme.dist.name = 'mkdocs2'
|
||||
theme.load().__file__ = os.path.join(path, '__init__.py')
|
||||
|
||||
mock_iter.return_value = iter([theme])
|
||||
mock_iter.return_value = [theme]
|
||||
|
||||
self.assertEqual(utils.get_theme_dir(theme.name), os.path.abspath(path))
|
||||
|
||||
@@ -269,53 +269,51 @@ class UtilsTests(unittest.TestCase):
|
||||
|
||||
self.assertRaises(KeyError, utils.get_theme_dir, 'nonexistanttheme')
|
||||
|
||||
@mock.patch('pkg_resources.iter_entry_points', autospec=True)
|
||||
@mock.patch('importlib_metadata.entry_points', autospec=True)
|
||||
def test_get_theme_dir_importerror(self, mock_iter):
|
||||
|
||||
theme = mock.Mock()
|
||||
theme.name = 'mkdocs2'
|
||||
theme.dist.key = 'mkdocs2'
|
||||
theme.dist.name = 'mkdocs2'
|
||||
theme.load.side_effect = ImportError()
|
||||
|
||||
mock_iter.return_value = iter([theme])
|
||||
mock_iter.return_value = [theme]
|
||||
|
||||
self.assertRaises(ImportError, utils.get_theme_dir, theme.name)
|
||||
|
||||
@mock.patch('pkg_resources.iter_entry_points', autospec=True)
|
||||
@mock.patch('importlib_metadata.entry_points', autospec=True)
|
||||
def test_get_themes_warning(self, mock_iter):
|
||||
|
||||
theme1 = mock.Mock()
|
||||
theme1.name = 'mkdocs2'
|
||||
theme1.dist.key = 'mkdocs2'
|
||||
theme1.dist.name = 'mkdocs2'
|
||||
theme1.load().__file__ = "some/path1"
|
||||
|
||||
theme2 = mock.Mock()
|
||||
theme2.name = 'mkdocs2'
|
||||
theme2.dist.key = 'mkdocs3'
|
||||
theme2.dist.name = 'mkdocs3'
|
||||
theme2.load().__file__ = "some/path2"
|
||||
|
||||
mock_iter.return_value = iter([theme1, theme2])
|
||||
mock_iter.return_value = [theme1, theme2]
|
||||
|
||||
self.assertEqual(
|
||||
sorted(utils.get_theme_names()),
|
||||
sorted(['mkdocs2', ]))
|
||||
|
||||
@mock.patch('pkg_resources.iter_entry_points', autospec=True)
|
||||
@mock.patch('pkg_resources.get_entry_map', autospec=True)
|
||||
def test_get_themes_error(self, mock_get, mock_iter):
|
||||
@mock.patch('importlib_metadata.entry_points', autospec=True)
|
||||
def test_get_themes_error(self, mock_iter):
|
||||
|
||||
theme1 = mock.Mock()
|
||||
theme1.name = 'mkdocs'
|
||||
theme1.dist.key = 'mkdocs'
|
||||
theme1.dist.name = 'mkdocs'
|
||||
theme1.load().__file__ = "some/path1"
|
||||
|
||||
theme2 = mock.Mock()
|
||||
theme2.name = 'mkdocs'
|
||||
theme2.dist.key = 'mkdocs2'
|
||||
theme2.dist.name = 'mkdocs2'
|
||||
theme2.load().__file__ = "some/path2"
|
||||
|
||||
mock_iter.return_value = iter([theme1, theme2])
|
||||
mock_get.return_value = {'mkdocs': theme1, }
|
||||
mock_iter.return_value = [theme1, theme2]
|
||||
|
||||
self.assertRaises(exceptions.ConfigurationError, utils.get_theme_names)
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ and structure of the site and pages in the site.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pkg_resources
|
||||
import shutil
|
||||
import re
|
||||
import yaml
|
||||
import fnmatch
|
||||
import posixpath
|
||||
import functools
|
||||
import importlib_metadata
|
||||
from datetime import datetime, timezone
|
||||
from urllib.parse import urlparse
|
||||
from yaml_env_tag import construct_env_tag
|
||||
@@ -316,23 +316,24 @@ def get_theme_dir(name):
|
||||
|
||||
|
||||
def get_themes():
|
||||
""" Return a dict of all installed themes as (name, entry point) pairs. """
|
||||
""" Return a dict of all installed themes as {name: EntryPoint}. """
|
||||
|
||||
themes = {}
|
||||
builtins = pkg_resources.get_entry_map(dist='mkdocs', group='mkdocs.themes')
|
||||
eps = importlib_metadata.entry_points(group='mkdocs.themes')
|
||||
builtins = [ep.name for ep in eps if ep.dist.name == 'mkdocs']
|
||||
|
||||
for theme in pkg_resources.iter_entry_points(group='mkdocs.themes'):
|
||||
for theme in eps:
|
||||
|
||||
if theme.name in builtins and theme.dist.key != 'mkdocs':
|
||||
if theme.name in builtins and theme.dist.name != 'mkdocs':
|
||||
raise exceptions.ConfigurationError(
|
||||
"The theme {} is a builtin theme but {} provides a theme "
|
||||
"with the same name".format(theme.name, theme.dist.key))
|
||||
|
||||
f"The theme '{theme.name}' is a builtin theme but the package '{theme.dist.name}' "
|
||||
"attempts to provide a theme with the same name."
|
||||
)
|
||||
elif theme.name in themes:
|
||||
multiple_packages = [themes[theme.name].dist.key, theme.dist.key]
|
||||
log.warning("The theme %s is provided by the Python packages "
|
||||
"'%s'. The one in %s will be used.",
|
||||
theme.name, ','.join(multiple_packages), theme.dist.key)
|
||||
log.warning(
|
||||
f"A theme named '{theme.name}' is provided by the Python packages '{theme.dist.name}'"
|
||||
f"and '{themes[theme.name].dist.name}'. The one in '{theme.dist.name}' will be used."
|
||||
)
|
||||
|
||||
themes[theme.name] = theme
|
||||
|
||||
|
||||
@@ -8,3 +8,4 @@ mdx_gh_links==0.2
|
||||
ghp-import==1.0
|
||||
pyyaml_env_tag==0.1
|
||||
mkdocs-redirects==1.0.1
|
||||
importlib_metadata==3.10.0
|
||||
|
||||
@@ -8,3 +8,4 @@ mdx_gh_links>=0.2
|
||||
ghp-import>=1.0
|
||||
pyyaml_env_tag>=0.1
|
||||
mkdocs-redirects>=1.0.1
|
||||
importlib_metadata>=3.10
|
||||
|
||||
Reference in New Issue
Block a user