Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions hotdoc/extensions/gi/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import os
from collections import namedtuple
import pathlib
import traceback

import pkg_resources
from backports.entry_points_selectable import entry_points

from hotdoc.core.links import Link
from hotdoc.utils.loggable import info, debug


NS_MAP = {'core': 'http://www.gtk.org/introspection/core/1.0',
Expand Down Expand Up @@ -200,16 +202,17 @@ def get_language_classes():
Banana banana
"""
all_classes = {}
deps_map = {}

for entry_point in pkg_resources.iter_entry_points(
group='hotdoc.extensions.gi.languages', name='get_language_classes'):
for entry_point in entry_points(
group='hotdoc.extensions.gi.languages',
name='get_language_classes'):
try:
ep_name = entry_point.name
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is here (despite ep_name never being used) because the results of importlib.metadata.entry_points() are documented as not being validated; invoking any property is the suggested means of triggering validation.

activation_function = entry_point.load()
classes = activation_function()
# pylint: disable=broad-except
except Exception as exc:
info("Failed to load %s" % entry_point.module_name, exc)
info("Failed to load %s" % str(entry_point), exc)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the same token, entry_point.name (the equivalent of entry_point.module_name from pkg_resources isn't necessarily going to exist on every result from entry_points(), so we can't rely on it for logging. Logging the string value of entry_point ensures that it'll be logged even if it isn't a valid EntryPoint object.

debug(traceback.format_exc())
continue

Expand Down
83 changes: 49 additions & 34 deletions hotdoc/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@
import sys
import re
import pathlib
import itertools
import traceback
import importlib.util

from urllib.request import urlretrieve
from pathlib import Path

import pkg_resources
from backports.entry_points_selectable import entry_points
try:
import importlib.metadata as meta
except ImportError:
import importlib_metadata as meta

from toposort import toposort_flatten

from hotdoc.core.exceptions import HotdocSourceException, ConfigError
Expand Down Expand Up @@ -143,39 +149,55 @@ def get_mtime(filename):
return -1


def __load_entry_point(
entry_point: meta.EntryPoint, is_installed: bool = False
) -> T.List[T.Type['Extension']]:
try:
ep_name = entry_point.name
activation_function = entry_point.load()
classes = activation_function()
# pylint: disable=broad-except
except Exception as exc:
if is_installed:
info(f"Failed to load {entry_point}", exc)
else:
warn('extension-import', f"Failed to load {entry_point} {exc}")
debug(traceback.format_exc())
return []
return classes


def __get_extra_extension_classes(paths):
"""
Banana banana
Identify and load extension packages from external paths.
"""
extra_classes = []
wset = pkg_resources.WorkingSet([])
distributions, _ = wset.find_plugins(pkg_resources.Environment(paths))

for dist in distributions:
sys.path.append(dist.location)
wset.add(dist)

for entry_point in wset.iter_entry_points(group='hotdoc.extensions',
name='get_extension_classes'):
try:
activation_function = entry_point.load()
classes = activation_function()
# pylint: disable=broad-except
except Exception as exc:
warn('extension-import', "Failed to load %s %s" %
(entry_point.module_name, exc))
debug(traceback.format_exc())
continue

for klass in classes:
extra_classes.append(klass)
path_dists = {
path: meta.distributions(path=[path])
for path in paths
}

for path, dists in path_dists.items():
entry_points = [
dist.entry_points.select(
group='hotdoc.extensions',
name='get_extension_classes')
for dist in dists
]
if entry_points:
sys.path.append(path)

for entry_point in itertools.chain(*entry_points):
classes = __load_entry_point(entry_point, False)
extra_classes.extend(classes)

return extra_classes


def __load_extra_extension_modules(paths: T.List[str]) -> T.List[T.Type['Extension']]:
"""
Banana banana
Load individual extension modules from specified file paths.
"""
extra_classes = []
for p in [Path(x) for x in paths]:
Expand All @@ -189,7 +211,7 @@ def __load_extra_extension_modules(paths: T.List[str]) -> T.List[T.Type['Extensi
spec.loader.exec_module(ext_mod)
extra_classes += ext_mod.get_extension_classes()
except Exception as exc:
warn('extension-import', f'Faield to import extension {p}')
warn('extension-import', f'Failed to import extension {p}')
return extra_classes


Expand All @@ -204,18 +226,11 @@ def get_extension_classes(sort: bool,
all_classes = {}
deps_map = {}

for entry_point in pkg_resources.iter_entry_points(
for entry_point in entry_points(
group='hotdoc.extensions', name='get_extension_classes'):
if entry_point.module_name == 'hotdoc_c_extension.extensions':
continue
try:
activation_function = entry_point.load()
classes = activation_function()
# pylint: disable=broad-except
except Exception as exc:
info("Failed to load %s" % entry_point.module_name, exc)
debug(traceback.format_exc())
if getattr(entry_point, 'module', '') == 'hotdoc_c_extension.extensions':
continue
classes = __load_entry_point(entry_point, True)

for klass in classes:
all_classes[klass.extension_name] = klass
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ def run_tests(self):
'appdirs',
'wheezy.template',
'toposort>=1.4',
'importlib_metadata; python_version<"3.10"',
'backports.entry_points_selectable',
]

# dbus-deviation requires sphinx, which requires python 3.5
Expand Down