Skip to content

Commit 051973a

Browse files
authored
Migrate from pkg_resources to importlib.metadata (#299)
1 parent 9e9014c commit 051973a

File tree

4 files changed

+46
-22
lines changed

4 files changed

+46
-22
lines changed

CHANGELOG.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
2.4.3 (in development)
1+
2.5.0 (in development)
22
----------------------
33

44
* Add support for the rinohtype builder (reported by brechtm, see issue #275).
55

6+
* Migrate from ``pkg_resources`` to ``importlib.metadata``. A side effect of
7+
this migration is that
8+
**plugins registered at runtime are longer exposed as entry points**.
9+
This is because ``importlib`` does not allow runtime modification of
10+
entry points.
11+
612
2.4.2 (10 April 2022)
713
---------------------
814

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ docutils>=0.8
33
pybtex>=0.24
44
pybtex-docutils>=1.0.0
55
dataclasses; python_version < '3.7'
6+
importlib_metadata>=3.6; python_version < '3.10'

src/sphinxcontrib/bibtex/plugin.py

+33-16
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,47 @@
1-
import pkg_resources
2-
from pybtex.plugin import _FakeEntryPoint
3-
from typing import Type, Any, Dict
1+
import sys
2+
if sys.version_info >= (3, 10):
3+
from importlib.metadata import entry_points, EntryPoint
4+
else:
5+
from importlib_metadata import entry_points, EntryPoint
6+
from typing import Type, Any, Dict, List
7+
8+
_runtime_plugins: Dict[str, Dict[str, Type]] = {
9+
'sphinxcontrib.bibtex.style.referencing': {}}
10+
11+
12+
# wrapper to work around missing type annotations for entry_points function
13+
def _entry_points(group: str, name: str) -> List[EntryPoint]:
14+
return entry_points(group=group, name=name) # type: ignore
415

516

617
def find_plugin(group: str, name: str) -> Type[Any]:
7-
"""Load a sphinxcontrib-bibtex plugin."""
8-
dist = pkg_resources.get_distribution('sphinxcontrib-bibtex')
9-
if group not in dist.get_entry_map():
18+
"""Load a sphinxcontrib-bibtex plugin, either from the runtime store,
19+
or from the entry points.
20+
"""
21+
global _runtime_plugins
22+
if group not in _runtime_plugins:
1023
raise ImportError(f"plugin group {group} not found")
11-
for entry_point in pkg_resources.iter_entry_points(group, name):
12-
return entry_point.load()
24+
try:
25+
return _runtime_plugins[group][name]
26+
except KeyError:
27+
for entry_point in _entry_points(group=group, name=name):
28+
return entry_point.load()
1329
raise ImportError(f"plugin {group}.{name} not found")
1430

1531

1632
def register_plugin(group: str, name: str, klass: Type[Any],
1733
force: bool = False) -> bool:
18-
"""Register a sphinxcontrib-bibtex plugin at runtime."""
19-
dist = pkg_resources.get_distribution('sphinxcontrib-bibtex')
20-
entry_map: Dict[str, Dict[str, pkg_resources.EntryPoint]] \
21-
= dist.get_entry_map()
34+
"""Register a sphinxcontrib-bibtex plugin into the runtime store."""
35+
global _runtime_plugins
36+
if group not in _runtime_plugins:
37+
raise ImportError(f"plugin group {group} not found")
38+
eps: List[Any]
2239
try:
23-
entry_points = entry_map[group]
40+
eps = [_runtime_plugins[group][name]]
2441
except KeyError:
25-
raise ImportError(f"plugin group {group} not found")
26-
if name not in entry_points or force:
27-
entry_points[name] = _FakeEntryPoint(name, klass)
42+
eps = _entry_points(group=group, name=name)
43+
if not eps or force:
44+
_runtime_plugins[group][name] = klass
2845
return True
2946
else:
3047
return False

src/sphinxcontrib/bibtex/style/template.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from sphinxcontrib.bibtex.nodes import raw_latex
2828
from sphinxcontrib.bibtex.richtext import BaseReferenceText
2929

30-
from typing import TYPE_CHECKING, Dict, Any, cast, NamedTuple
30+
from typing import TYPE_CHECKING, Dict, Any, cast, NamedTuple, List
3131

3232
if TYPE_CHECKING:
3333
from pybtex.backends import BaseBackend
@@ -123,7 +123,7 @@ class SphinxReferenceText(BaseReferenceText[SphinxReferenceInfo]):
123123
for use with :class:`SphinxReferenceInfo`.
124124
"""
125125

126-
def render(self, backend: "BaseBackend"):
126+
def render(self, backend: "BaseBackend") -> List[docutils.nodes.Element]:
127127
assert isinstance(backend, pybtex_docutils.Backend), \
128128
"SphinxReferenceText only supports the docutils backend"
129129
info = self.info[0]
@@ -144,16 +144,16 @@ def render(self, backend: "BaseBackend"):
144144
else:
145145
children = super().render(backend)
146146
# make_refnode only takes a single child
147-
refnode = make_refnode(
147+
refnode2 = make_refnode(
148148
builder=info.builder,
149149
fromdocname=info.fromdocname,
150150
todocname=info.todocname,
151151
targetid=info.citation_id,
152152
child=children[0],
153153
title=info.title,
154154
)
155-
refnode.extend(children[1:]) # type: ignore
156-
return [refnode]
155+
refnode2.extend(children[1:]) # type: ignore
156+
return [refnode2]
157157

158158

159159
@node

0 commit comments

Comments
 (0)