Skip to content

Commit 1f89612

Browse files
committed
Add module discovery via pkg_resources EntryPoints.
1 parent b787b7d commit 1f89612

File tree

1 file changed

+56
-3
lines changed

1 file changed

+56
-3
lines changed

bitbot/ModuleManager.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import enum, gc, glob, importlib, importlib.util, io, inspect, os, sys
2+
from pkg_resources import iter_entry_points
23
import typing, uuid
34
from . import Config, EventManager, Exports, IRCBot, Logging, Timers, utils
45

@@ -117,19 +118,62 @@ def __init__(self,
117118
def _list_modules(self, directory: str
118119
) -> typing.Dict[str, ModuleDefinition]:
119120
modules = []
121+
120122
for file_module in glob.glob(os.path.join(directory, "*.py")):
121-
modules.append(self.define_module(ModuleType.FILE, file_module))
123+
# Excluse __init__.py, etc.
124+
if not file_module.rsplit(os.path.sep)[-1].startswith('_'):
125+
modules.append(self.define_module(ModuleType.FILE, file_module))
122126

123127
for directory_module in glob.glob(os.path.join(
124128
directory, "*", "__init__.py")):
125129
modules.append(self.define_module(ModuleType.DIRECTORY,
126130
directory_module))
127131
return {definition.name: definition for definition in modules}
128132

133+
def _list_installed_modules(self, entry_point_group
134+
) -> typing.Dict[str, ModuleDefinition]:
135+
"""Finds modules installed using a pkg_resources EntryPoint.
136+
137+
They are installed by `setuptools` by using:
138+
139+
```
140+
setup(
141+
# ...
142+
entry_points={
143+
'bitbot.extra_modules': [
144+
'module_name = your_package_name.your_module_name:Module',
145+
# ...
146+
}
147+
}
148+
)
149+
```
150+
151+
(replace only `module_name`, `your_package_name`, and
152+
`your_module_name` on the example above)
153+
"""
154+
modules = {}
155+
156+
for entry_point in iter_entry_points(entry_point_group):
157+
module_class = entry_point.load()
158+
path = sys.modules[module_class.__module__].__file__
159+
if path.rsplit(os.path.sep, 1)[-1] == '__init__.py':
160+
type = ModuleType.DIRECTORY
161+
else:
162+
type = ModuleType.FILE
163+
modules[entry_point.name] = self.define_module(type, path)
164+
165+
return modules
166+
129167
def list_modules(self, whitelist: typing.List[str],
130168
blacklist: typing.List[str]) -> typing.Dict[str, ModuleDefinition]:
131-
core_modules = self._list_modules(self._core_modules)
132-
extra_modules: typing.Dict[str, ModuleDefinition] = {}
169+
"""Discovers modules that are either installed or in one of the
170+
directories listed by `[self._core_modules] + self._extra_modules`."""
171+
172+
core_modules = self._list_installed_modules('bitbot.core_modules')
173+
extra_modules = self._list_installed_modules('bitbot.extra_modules')
174+
175+
for name, module in self._list_modules(self._core_modules).items():
176+
core_modules[name] = module
133177

134178
for directory in self._extra_modules:
135179
for name, module in self._list_modules(directory).items():
@@ -179,6 +223,15 @@ def _module_name(self, path: str) -> str:
179223
return os.path.basename(path).rsplit(".py", 1)[0].lower()
180224
def _module_paths(self, name: str) -> typing.List[str]:
181225
paths = []
226+
227+
entry_points = (
228+
iter_entry_points('bitbot.core_modules', name)
229+
+ iter_entry_points('bitbot.extra_modules', name))
230+
231+
for entry_point in entry_points:
232+
module_class = entry_point.load()
233+
paths.append(sys.modules[module_class.__module__].__path__)
234+
182235
for directory in [self._core_modules]+self._extra_modules:
183236
paths.append(os.path.join(directory, name))
184237
return paths

0 commit comments

Comments
 (0)