Skip to content
Closed
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
8 changes: 8 additions & 0 deletions meshroom/_plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
""" Plugins.
"""
# Plugins
from .node import NodePluginManager
from .base import Status, Pluginator


__all__ = ["NodePluginManager", "Status", "Pluginator"]
92 changes: 92 additions & 0 deletions meshroom/_plugins/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
""" Base functionality for Plugins.
"""
# Types
from typing import List

# STD
from contextlib import contextmanager
import enum
import importlib
import inspect
import logging
import pkgutil


class Status(enum.IntEnum):
""" Enum describing the state of the plugin.
"""

# UNLOADED or NOT Available - Describing that the plugin is not available in the current set of plugins
UNLOADED = -1

# ERRORED describes that the plugin exists but could not be loaded due to errors with the structure
ERRORED = 0

# LOADED describes that the plugin is currently loaded and is fully functional
LOADED = 1


class Pluginator:
""" The common plugin utilities.
"""

@staticmethod
@contextmanager
def add_to_path(_p):
""" A Context Manager to add the provided path to Python's sys.path temporarily.
"""
import sys # pylint: disable=import-outside-toplevel
old_path = sys.path
sys.path = sys.path[:]
sys.path.insert(0, _p)
try:
yield
finally:
sys.path = old_path

@staticmethod
def get(folder, packageName, classType) -> List:
""" Returns Array of Plugin, each holding the plugin and the module it belongs to.

Args:
folder (str): Path to the Directory.
packageName (str): Name of the package to import.
classType (desc.Node | BaseSubmitter): The base type of plugin which is being imported.
"""
pluginTypes = []
errors = []

# temporarily add folder to python path
with Pluginator.add_to_path(folder):
# import node package
package = importlib.import_module(packageName)
packageName = package.packageName if hasattr(package, 'packageName') else package.__name__
packageVersion = getattr(package, "__version__", None)

for importer, pluginName, ispkg in pkgutil.iter_modules(package.__path__):
pluginModuleName = '.' + pluginName

try:
pluginMod = importlib.import_module(pluginModuleName, package=package.__name__)
plugins = [plugin for name, plugin in inspect.getmembers(pluginMod, inspect.isclass)
if plugin.__module__ == '{}.{}'.format(package.__name__, pluginName)
and issubclass(plugin, classType)]
if not plugins:
logging.warning("No class defined in plugin: {}".format(pluginModuleName))

# Update the package name and version on the plugin
for p in plugins:
p.packageName = packageName
p.packageVersion = packageVersion

# Extend all of the plugins
pluginTypes.extend(plugins)
except Exception as exc:
errors.append(' * {}: {}'.format(pluginName, str(exc)))

if errors:
logging.warning('== The following "{package}" plugins could not be loaded ==\n'
'{errorMsg}\n'
.format(package=packageName, errorMsg='\n'.join(errors)))

return pluginTypes
Loading