mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-19 12:59:36 -07:00
add lib for subliminal and set non-intrusive default ionice.
This commit is contained in:
parent
8733655846
commit
798cc62a96
8 changed files with 915 additions and 3 deletions
|
@ -32,11 +32,11 @@
|
||||||
[Posix]
|
[Posix]
|
||||||
### Process priority setting for External commands (Extractor and Transcoder) on Posix (Unix/Linux/OSX) systems.
|
### Process priority setting for External commands (Extractor and Transcoder) on Posix (Unix/Linux/OSX) systems.
|
||||||
# Set the Niceness value for the nice command. These range from -20 (most favorable to the process) to 19 (least favorable to the process).
|
# Set the Niceness value for the nice command. These range from -20 (most favorable to the process) to 19 (least favorable to the process).
|
||||||
niceness = 10
|
niceness = 0
|
||||||
# Set the ionice scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle.
|
# Set the ionice scheduling class. 0 for none, 1 for real time, 2 for best-effort, 3 for idle.
|
||||||
ionice_class = 2
|
ionice_class = 0
|
||||||
# Set the ionice scheduling class data. This defines the class data, if the class accepts an argument. For real time and best-effort, 0-7 is valid data.
|
# Set the ionice scheduling class data. This defines the class data, if the class accepts an argument. For real time and best-effort, 0-7 is valid data.
|
||||||
ionice_classdata = 4
|
ionice_classdata = 0
|
||||||
|
|
||||||
[CouchPotato]
|
[CouchPotato]
|
||||||
#### autoProcessing for Movies
|
#### autoProcessing for Movies
|
||||||
|
|
36
libs/stevedore/__init__.py
Executable file
36
libs/stevedore/__init__.py
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'ExtensionManager',
|
||||||
|
'EnabledExtensionManager',
|
||||||
|
'NamedExtensionManager',
|
||||||
|
'HookManager',
|
||||||
|
'DriverManager',
|
||||||
|
]
|
||||||
|
|
||||||
|
from .extension import ExtensionManager
|
||||||
|
from .enabled import EnabledExtensionManager
|
||||||
|
from .named import NamedExtensionManager
|
||||||
|
from .hook import HookManager
|
||||||
|
from .driver import DriverManager
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Configure a NullHandler for our log messages in case
|
||||||
|
# the app we're used from does not set up logging.
|
||||||
|
LOG = logging.getLogger('stevedore')
|
||||||
|
|
||||||
|
if hasattr(logging, 'NullHandler'):
|
||||||
|
LOG.addHandler(logging.NullHandler())
|
||||||
|
else:
|
||||||
|
class NullHandler(logging.Handler):
|
||||||
|
def handle(self, record):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def emit(self, record):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def createLock(self):
|
||||||
|
self.lock = None
|
||||||
|
|
||||||
|
LOG.addHandler(NullHandler())
|
216
libs/stevedore/dispatch.py
Executable file
216
libs/stevedore/dispatch.py
Executable file
|
@ -0,0 +1,216 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from .enabled import EnabledExtensionManager
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DispatchExtensionManager(EnabledExtensionManager):
|
||||||
|
"""Loads all plugins and filters on execution.
|
||||||
|
|
||||||
|
This is useful for long-running processes that need to pass
|
||||||
|
different inputs to different extensions.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param check_func: Function to determine which extensions to load.
|
||||||
|
:type check_func: callable
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged and
|
||||||
|
then ignored
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
def map(self, filter_func, func, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking func() for any where
|
||||||
|
filter_func() returns True.
|
||||||
|
|
||||||
|
The signature of filter_func() should be::
|
||||||
|
|
||||||
|
def filter_func(ext, *args, **kwds):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The first argument to filter_func(), 'ext', is the
|
||||||
|
:class:`~stevedore.extension.Extension`
|
||||||
|
instance. filter_func() should return True if the extension
|
||||||
|
should be invoked for the input arguments.
|
||||||
|
|
||||||
|
The signature for func() should be::
|
||||||
|
|
||||||
|
def func(ext, *args, **kwds):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The first argument to func(), 'ext', is the
|
||||||
|
:class:`~stevedore.extension.Extension` instance.
|
||||||
|
|
||||||
|
Exceptions raised from within func() are propagated up and
|
||||||
|
processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
:param filter_func: Callable to test each extension.
|
||||||
|
:param func: Callable to invoke for each extension.
|
||||||
|
:param args: Variable arguments to pass to func()
|
||||||
|
:param kwds: Keyword arguments to pass to func()
|
||||||
|
:returns: List of values returned from func()
|
||||||
|
"""
|
||||||
|
if not self.extensions:
|
||||||
|
# FIXME: Use a more specific exception class here.
|
||||||
|
raise RuntimeError('No %s extensions found' % self.namespace)
|
||||||
|
response = []
|
||||||
|
for e in self.extensions:
|
||||||
|
if filter_func(e, *args, **kwds):
|
||||||
|
self._invoke_one_plugin(response.append, func, e, args, kwds)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def map_method(self, filter_func, method_name, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking each one's object method called
|
||||||
|
`method_name` for any where filter_func() returns True.
|
||||||
|
|
||||||
|
This is equivalent of using :meth:`map` with func set to
|
||||||
|
`lambda x: x.obj.method_name()`
|
||||||
|
while being more convenient.
|
||||||
|
|
||||||
|
Exceptions raised from within the called method are propagated up
|
||||||
|
and processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
.. versionadded:: 0.12
|
||||||
|
|
||||||
|
:param filter_func: Callable to test each extension.
|
||||||
|
:param method_name: The extension method name to call
|
||||||
|
for each extension.
|
||||||
|
:param args: Variable arguments to pass to method
|
||||||
|
:param kwds: Keyword arguments to pass to method
|
||||||
|
:returns: List of values returned from methods
|
||||||
|
"""
|
||||||
|
return self.map(filter_func, self._call_extension_method,
|
||||||
|
method_name, *args, **kwds)
|
||||||
|
|
||||||
|
|
||||||
|
class NameDispatchExtensionManager(DispatchExtensionManager):
|
||||||
|
"""Loads all plugins and filters on execution.
|
||||||
|
|
||||||
|
This is useful for long-running processes that need to pass
|
||||||
|
different inputs to different extensions and can predict the name
|
||||||
|
of the extensions before calling them.
|
||||||
|
|
||||||
|
The check_func argument should return a boolean, with ``True``
|
||||||
|
indicating that the extension should be loaded and made available
|
||||||
|
and ``False`` indicating that the extension should be ignored.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param check_func: Function to determine which extensions to load.
|
||||||
|
:type check_func: callable
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged and
|
||||||
|
then ignored
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace, check_func, invoke_on_load=False,
|
||||||
|
invoke_args=(), invoke_kwds={},
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
super(NameDispatchExtensionManager, self).__init__(
|
||||||
|
namespace=namespace,
|
||||||
|
check_func=check_func,
|
||||||
|
invoke_on_load=invoke_on_load,
|
||||||
|
invoke_args=invoke_args,
|
||||||
|
invoke_kwds=invoke_kwds,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback,
|
||||||
|
verify_requirements=verify_requirements,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _init_plugins(self, extensions):
|
||||||
|
super(NameDispatchExtensionManager, self)._init_plugins(extensions)
|
||||||
|
self.by_name = dict((e.name, e) for e in self.extensions)
|
||||||
|
|
||||||
|
def map(self, names, func, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking func() for any where
|
||||||
|
the name is in the given list of names.
|
||||||
|
|
||||||
|
The signature for func() should be::
|
||||||
|
|
||||||
|
def func(ext, *args, **kwds):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The first argument to func(), 'ext', is the
|
||||||
|
:class:`~stevedore.extension.Extension` instance.
|
||||||
|
|
||||||
|
Exceptions raised from within func() are propagated up and
|
||||||
|
processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
:param names: List or set of name(s) of extension(s) to invoke.
|
||||||
|
:param func: Callable to invoke for each extension.
|
||||||
|
:param args: Variable arguments to pass to func()
|
||||||
|
:param kwds: Keyword arguments to pass to func()
|
||||||
|
:returns: List of values returned from func()
|
||||||
|
"""
|
||||||
|
response = []
|
||||||
|
for name in names:
|
||||||
|
try:
|
||||||
|
e = self.by_name[name]
|
||||||
|
except KeyError:
|
||||||
|
LOG.debug('Missing extension %r being ignored', name)
|
||||||
|
else:
|
||||||
|
self._invoke_one_plugin(response.append, func, e, args, kwds)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def map_method(self, names, method_name, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking each one's object method called
|
||||||
|
`method_name` for any where the name is in the given list of names.
|
||||||
|
|
||||||
|
This is equivalent of using :meth:`map` with func set to
|
||||||
|
`lambda x: x.obj.method_name()`
|
||||||
|
while being more convenient.
|
||||||
|
|
||||||
|
Exceptions raised from within the called method are propagated up
|
||||||
|
and processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
.. versionadded:: 0.12
|
||||||
|
|
||||||
|
:param names: List or set of name(s) of extension(s) to invoke.
|
||||||
|
:param method_name: The extension method name
|
||||||
|
to call for each extension.
|
||||||
|
:param args: Variable arguments to pass to method
|
||||||
|
:param kwds: Keyword arguments to pass to method
|
||||||
|
:returns: List of values returned from methods
|
||||||
|
"""
|
||||||
|
return self.map(names, self._call_extension_method,
|
||||||
|
method_name, *args, **kwds)
|
126
libs/stevedore/driver.py
Executable file
126
libs/stevedore/driver.py
Executable file
|
@ -0,0 +1,126 @@
|
||||||
|
from .named import NamedExtensionManager
|
||||||
|
|
||||||
|
|
||||||
|
class DriverManager(NamedExtensionManager):
|
||||||
|
"""Load a single plugin with a given name from the namespace.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param name: The name of the driver to load.
|
||||||
|
:type name: str
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace, name,
|
||||||
|
invoke_on_load=False, invoke_args=(), invoke_kwds={},
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
super(DriverManager, self).__init__(
|
||||||
|
namespace=namespace,
|
||||||
|
names=[name],
|
||||||
|
invoke_on_load=invoke_on_load,
|
||||||
|
invoke_args=invoke_args,
|
||||||
|
invoke_kwds=invoke_kwds,
|
||||||
|
on_load_failure_callback=on_load_failure_callback,
|
||||||
|
verify_requirements=verify_requirements,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_test_instance(cls, extension, namespace='TESTING',
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
"""Construct a test DriverManager
|
||||||
|
|
||||||
|
Test instances are passed a list of extensions to work from rather
|
||||||
|
than loading them from entry points.
|
||||||
|
|
||||||
|
:param extension: Pre-configured Extension instance
|
||||||
|
:type extension: :class:`~stevedore.extension.Extension`
|
||||||
|
:param namespace: The namespace for the manager; used only for
|
||||||
|
identification since the extensions are passed in.
|
||||||
|
:type namespace: str
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged
|
||||||
|
and then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will
|
||||||
|
be called when a entrypoint can not be loaded. The
|
||||||
|
arguments that will be provided when this is called (when
|
||||||
|
an entrypoint fails to load) are (manager, entrypoint,
|
||||||
|
exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
:return: The manager instance, initialized for testing
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
o = super(DriverManager, cls).make_test_instance(
|
||||||
|
[extension], namespace=namespace,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback,
|
||||||
|
verify_requirements=verify_requirements)
|
||||||
|
return o
|
||||||
|
|
||||||
|
def _init_plugins(self, extensions):
|
||||||
|
super(DriverManager, self)._init_plugins(extensions)
|
||||||
|
|
||||||
|
if not self.extensions:
|
||||||
|
name = self._names[0]
|
||||||
|
raise RuntimeError('No %r driver found, looking for %r' %
|
||||||
|
(self.namespace, name))
|
||||||
|
if len(self.extensions) > 1:
|
||||||
|
discovered_drivers = ','.join(e.entry_point_target
|
||||||
|
for e in self.extensions)
|
||||||
|
|
||||||
|
raise RuntimeError('Multiple %r drivers found: %s' %
|
||||||
|
(self.namespace, discovered_drivers))
|
||||||
|
|
||||||
|
def __call__(self, func, *args, **kwds):
|
||||||
|
"""Invokes func() for the single loaded extension.
|
||||||
|
|
||||||
|
The signature for func() should be::
|
||||||
|
|
||||||
|
def func(ext, *args, **kwds):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The first argument to func(), 'ext', is the
|
||||||
|
:class:`~stevedore.extension.Extension` instance.
|
||||||
|
|
||||||
|
Exceptions raised from within func() are logged and ignored.
|
||||||
|
|
||||||
|
:param func: Callable to invoke for each extension.
|
||||||
|
:param args: Variable arguments to pass to func()
|
||||||
|
:param kwds: Keyword arguments to pass to func()
|
||||||
|
:returns: List of values returned from func()
|
||||||
|
"""
|
||||||
|
results = self.map(func, *args, **kwds)
|
||||||
|
if results:
|
||||||
|
return results[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def driver(self):
|
||||||
|
"""Returns the driver being used by this manager.
|
||||||
|
"""
|
||||||
|
ext = self.extensions[0]
|
||||||
|
return ext.obj if ext.obj else ext.plugin
|
71
libs/stevedore/enabled.py
Executable file
71
libs/stevedore/enabled.py
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from .extension import ExtensionManager
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EnabledExtensionManager(ExtensionManager):
|
||||||
|
"""Loads only plugins that pass a check function.
|
||||||
|
|
||||||
|
The check_func argument should return a boolean, with ``True``
|
||||||
|
indicating that the extension should be loaded and made available
|
||||||
|
and ``False`` indicating that the extension should be ignored.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param check_func: Function to determine which extensions to load.
|
||||||
|
:type check_func: callable
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged and
|
||||||
|
then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace, check_func, invoke_on_load=False,
|
||||||
|
invoke_args=(), invoke_kwds={},
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False,):
|
||||||
|
self.check_func = check_func
|
||||||
|
super(EnabledExtensionManager, self).__init__(
|
||||||
|
namespace,
|
||||||
|
invoke_on_load=invoke_on_load,
|
||||||
|
invoke_args=invoke_args,
|
||||||
|
invoke_kwds=invoke_kwds,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback,
|
||||||
|
verify_requirements=verify_requirements,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _load_one_plugin(self, ep, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements):
|
||||||
|
ext = super(EnabledExtensionManager, self)._load_one_plugin(
|
||||||
|
ep, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements,
|
||||||
|
)
|
||||||
|
if ext and not self.check_func(ext):
|
||||||
|
LOG.debug('ignoring extension %r', ep.name)
|
||||||
|
return None
|
||||||
|
return ext
|
275
libs/stevedore/extension.py
Executable file
275
libs/stevedore/extension.py
Executable file
|
@ -0,0 +1,275 @@
|
||||||
|
"""ExtensionManager
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Extension(object):
|
||||||
|
"""Book-keeping object for tracking extensions.
|
||||||
|
|
||||||
|
The arguments passed to the constructor are saved as attributes of
|
||||||
|
the instance using the same names, and can be accessed by the
|
||||||
|
callables passed to :meth:`map` or when iterating over an
|
||||||
|
:class:`ExtensionManager` directly.
|
||||||
|
|
||||||
|
:param name: The entry point name.
|
||||||
|
:type name: str
|
||||||
|
:param entry_point: The EntryPoint instance returned by
|
||||||
|
:mod:`pkg_resources`.
|
||||||
|
:type entry_point: EntryPoint
|
||||||
|
:param plugin: The value returned by entry_point.load()
|
||||||
|
:param obj: The object returned by ``plugin(*args, **kwds)`` if the
|
||||||
|
manager invoked the extension on load.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, entry_point, plugin, obj):
|
||||||
|
self.name = name
|
||||||
|
self.entry_point = entry_point
|
||||||
|
self.plugin = plugin
|
||||||
|
self.obj = obj
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entry_point_target(self):
|
||||||
|
"""The module and attribute referenced by this extension's entry_point.
|
||||||
|
|
||||||
|
:return: A string representation of the target of the entry point in
|
||||||
|
'dotted.module:object' format.
|
||||||
|
"""
|
||||||
|
return '%s:%s' % (self.entry_point.module_name,
|
||||||
|
self.entry_point.attrs[0])
|
||||||
|
|
||||||
|
|
||||||
|
class ExtensionManager(object):
|
||||||
|
"""Base class for all of the other managers.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged and
|
||||||
|
then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace,
|
||||||
|
invoke_on_load=False,
|
||||||
|
invoke_args=(),
|
||||||
|
invoke_kwds={},
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
self._init_attributes(
|
||||||
|
namespace,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
extensions = self._load_plugins(invoke_on_load,
|
||||||
|
invoke_args,
|
||||||
|
invoke_kwds,
|
||||||
|
verify_requirements)
|
||||||
|
self._init_plugins(extensions)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_test_instance(cls, extensions, namespace='TESTING',
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
"""Construct a test ExtensionManager
|
||||||
|
|
||||||
|
Test instances are passed a list of extensions to work from rather
|
||||||
|
than loading them from entry points.
|
||||||
|
|
||||||
|
:param extensions: Pre-configured Extension instances to use
|
||||||
|
:type extensions: list of :class:`~stevedore.extension.Extension`
|
||||||
|
:param namespace: The namespace for the manager; used only for
|
||||||
|
identification since the extensions are passed in.
|
||||||
|
:type namespace: str
|
||||||
|
:param propagate_map_exceptions: When calling map, controls whether
|
||||||
|
exceptions are propagated up through the map call or whether they
|
||||||
|
are logged and then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will
|
||||||
|
be called when a entrypoint can not be loaded. The
|
||||||
|
arguments that will be provided when this is called (when
|
||||||
|
an entrypoint fails to load) are (manager, entrypoint,
|
||||||
|
exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
:return: The manager instance, initialized for testing
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
o = cls.__new__(cls)
|
||||||
|
o._init_attributes(namespace,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
o._init_plugins(extensions)
|
||||||
|
return o
|
||||||
|
|
||||||
|
def _init_attributes(self, namespace, propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None):
|
||||||
|
self.namespace = namespace
|
||||||
|
self.propagate_map_exceptions = propagate_map_exceptions
|
||||||
|
self._on_load_failure_callback = on_load_failure_callback
|
||||||
|
|
||||||
|
def _init_plugins(self, extensions):
|
||||||
|
self.extensions = extensions
|
||||||
|
self._extensions_by_name = None
|
||||||
|
|
||||||
|
ENTRY_POINT_CACHE = {}
|
||||||
|
|
||||||
|
def _find_entry_points(self, namespace):
|
||||||
|
if namespace not in self.ENTRY_POINT_CACHE:
|
||||||
|
eps = list(pkg_resources.iter_entry_points(namespace))
|
||||||
|
self.ENTRY_POINT_CACHE[namespace] = eps
|
||||||
|
return self.ENTRY_POINT_CACHE[namespace]
|
||||||
|
|
||||||
|
def _load_plugins(self, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements):
|
||||||
|
extensions = []
|
||||||
|
for ep in self._find_entry_points(self.namespace):
|
||||||
|
LOG.debug('found extension %r', ep)
|
||||||
|
try:
|
||||||
|
ext = self._load_one_plugin(ep,
|
||||||
|
invoke_on_load,
|
||||||
|
invoke_args,
|
||||||
|
invoke_kwds,
|
||||||
|
verify_requirements,
|
||||||
|
)
|
||||||
|
if ext:
|
||||||
|
extensions.append(ext)
|
||||||
|
except (KeyboardInterrupt, AssertionError):
|
||||||
|
raise
|
||||||
|
except Exception as err:
|
||||||
|
LOG.error('Could not load %r: %s', ep.name, err)
|
||||||
|
LOG.exception(err)
|
||||||
|
if self._on_load_failure_callback is not None:
|
||||||
|
self._on_load_failure_callback(self, ep, err)
|
||||||
|
return extensions
|
||||||
|
|
||||||
|
def _load_one_plugin(self, ep, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements):
|
||||||
|
plugin = ep.load(require=verify_requirements)
|
||||||
|
if invoke_on_load:
|
||||||
|
obj = plugin(*invoke_args, **invoke_kwds)
|
||||||
|
else:
|
||||||
|
obj = None
|
||||||
|
return Extension(ep.name, ep, plugin, obj)
|
||||||
|
|
||||||
|
def names(self):
|
||||||
|
"Returns the names of the discovered extensions"
|
||||||
|
# We want to return the names of the extensions in the order
|
||||||
|
# they would be used by map(), since some subclasses change
|
||||||
|
# that order.
|
||||||
|
return [e.name for e in self.extensions]
|
||||||
|
|
||||||
|
def map(self, func, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking func() for each.
|
||||||
|
|
||||||
|
The signature for func() should be::
|
||||||
|
|
||||||
|
def func(ext, *args, **kwds):
|
||||||
|
pass
|
||||||
|
|
||||||
|
The first argument to func(), 'ext', is the
|
||||||
|
:class:`~stevedore.extension.Extension` instance.
|
||||||
|
|
||||||
|
Exceptions raised from within func() are propagated up and
|
||||||
|
processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
:param func: Callable to invoke for each extension.
|
||||||
|
:param args: Variable arguments to pass to func()
|
||||||
|
:param kwds: Keyword arguments to pass to func()
|
||||||
|
:returns: List of values returned from func()
|
||||||
|
"""
|
||||||
|
if not self.extensions:
|
||||||
|
# FIXME: Use a more specific exception class here.
|
||||||
|
raise RuntimeError('No %s extensions found' % self.namespace)
|
||||||
|
response = []
|
||||||
|
for e in self.extensions:
|
||||||
|
self._invoke_one_plugin(response.append, func, e, args, kwds)
|
||||||
|
return response
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _call_extension_method(extension, method_name, *args, **kwds):
|
||||||
|
return getattr(extension.obj, method_name)(*args, **kwds)
|
||||||
|
|
||||||
|
def map_method(self, method_name, *args, **kwds):
|
||||||
|
"""Iterate over the extensions invoking a method by name.
|
||||||
|
|
||||||
|
This is equivalent of using :meth:`map` with func set to
|
||||||
|
`lambda x: x.obj.method_name()`
|
||||||
|
while being more convenient.
|
||||||
|
|
||||||
|
Exceptions raised from within the called method are propagated up
|
||||||
|
and processing stopped if self.propagate_map_exceptions is True,
|
||||||
|
otherwise they are logged and ignored.
|
||||||
|
|
||||||
|
.. versionadded:: 0.12
|
||||||
|
|
||||||
|
:param method_name: The extension method name
|
||||||
|
to call for each extension.
|
||||||
|
:param args: Variable arguments to pass to method
|
||||||
|
:param kwds: Keyword arguments to pass to method
|
||||||
|
:returns: List of values returned from methods
|
||||||
|
"""
|
||||||
|
return self.map(self._call_extension_method,
|
||||||
|
method_name, *args, **kwds)
|
||||||
|
|
||||||
|
def _invoke_one_plugin(self, response_callback, func, e, args, kwds):
|
||||||
|
try:
|
||||||
|
response_callback(func(e, *args, **kwds))
|
||||||
|
except Exception as err:
|
||||||
|
if self.propagate_map_exceptions:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
LOG.error('error calling %r: %s', e.name, err)
|
||||||
|
LOG.exception(err)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
"""Produce iterator for the manager.
|
||||||
|
|
||||||
|
Iterating over an ExtensionManager produces the :class:`Extension`
|
||||||
|
instances in the order they would be invoked.
|
||||||
|
"""
|
||||||
|
return iter(self.extensions)
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
"""Return the named extension.
|
||||||
|
|
||||||
|
Accessing an ExtensionManager as a dictionary (``em['name']``)
|
||||||
|
produces the :class:`Extension` instance with the
|
||||||
|
specified name.
|
||||||
|
"""
|
||||||
|
if self._extensions_by_name is None:
|
||||||
|
d = {}
|
||||||
|
for e in self.extensions:
|
||||||
|
d[e.name] = e
|
||||||
|
self._extensions_by_name = d
|
||||||
|
return self._extensions_by_name[name]
|
64
libs/stevedore/hook.py
Executable file
64
libs/stevedore/hook.py
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
from .named import NamedExtensionManager
|
||||||
|
|
||||||
|
|
||||||
|
class HookManager(NamedExtensionManager):
|
||||||
|
"""Coordinate execution of multiple extensions using a common name.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param name: The name of the hooks to load.
|
||||||
|
:type name: str
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace, name,
|
||||||
|
invoke_on_load=False, invoke_args=(), invoke_kwds={},
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
super(HookManager, self).__init__(
|
||||||
|
namespace,
|
||||||
|
[name],
|
||||||
|
invoke_on_load=invoke_on_load,
|
||||||
|
invoke_args=invoke_args,
|
||||||
|
invoke_kwds=invoke_kwds,
|
||||||
|
on_load_failure_callback=on_load_failure_callback,
|
||||||
|
verify_requirements=verify_requirements,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _init_attributes(self, namespace, names, name_order=False,
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None):
|
||||||
|
super(HookManager, self)._init_attributes(
|
||||||
|
namespace, names,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
self._name = names[0]
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
"""Return the named extensions.
|
||||||
|
|
||||||
|
Accessing a HookManager as a dictionary (``em['name']``)
|
||||||
|
produces a list of the :class:`Extension` instance(s) with the
|
||||||
|
specified name, in the order they would be invoked by map().
|
||||||
|
"""
|
||||||
|
if name != self._name:
|
||||||
|
raise KeyError(name)
|
||||||
|
return self.extensions
|
124
libs/stevedore/named.py
Executable file
124
libs/stevedore/named.py
Executable file
|
@ -0,0 +1,124 @@
|
||||||
|
from .extension import ExtensionManager
|
||||||
|
|
||||||
|
|
||||||
|
class NamedExtensionManager(ExtensionManager):
|
||||||
|
"""Loads only the named extensions.
|
||||||
|
|
||||||
|
This is useful for explicitly enabling extensions in a
|
||||||
|
configuration file, for example.
|
||||||
|
|
||||||
|
:param namespace: The namespace for the entry points.
|
||||||
|
:type namespace: str
|
||||||
|
:param names: The names of the extensions to load.
|
||||||
|
:type names: list(str)
|
||||||
|
:param invoke_on_load: Boolean controlling whether to invoke the
|
||||||
|
object returned by the entry point after the driver is loaded.
|
||||||
|
:type invoke_on_load: bool
|
||||||
|
:param invoke_args: Positional arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_args: tuple
|
||||||
|
:param invoke_kwds: Named arguments to pass when invoking
|
||||||
|
the object returned by the entry point. Only used if invoke_on_load
|
||||||
|
is True.
|
||||||
|
:type invoke_kwds: dict
|
||||||
|
:param name_order: If true, sort the loaded extensions to match the
|
||||||
|
order used in ``names``.
|
||||||
|
:type name_order: bool
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged and
|
||||||
|
then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will be called when
|
||||||
|
a entrypoint can not be loaded. The arguments that will be provided
|
||||||
|
when this is called (when an entrypoint fails to load) are
|
||||||
|
(manager, entrypoint, exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, namespace, names,
|
||||||
|
invoke_on_load=False, invoke_args=(), invoke_kwds={},
|
||||||
|
name_order=False, propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
self._init_attributes(
|
||||||
|
namespace, names, name_order=name_order,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
extensions = self._load_plugins(invoke_on_load,
|
||||||
|
invoke_args,
|
||||||
|
invoke_kwds,
|
||||||
|
verify_requirements)
|
||||||
|
self._init_plugins(extensions)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_test_instance(cls, extensions, namespace='TESTING',
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None,
|
||||||
|
verify_requirements=False):
|
||||||
|
"""Construct a test NamedExtensionManager
|
||||||
|
|
||||||
|
Test instances are passed a list of extensions to use rather than
|
||||||
|
loading them from entry points.
|
||||||
|
|
||||||
|
:param extensions: Pre-configured Extension instances
|
||||||
|
:type extensions: list of :class:`~stevedore.extension.Extension`
|
||||||
|
:param namespace: The namespace for the manager; used only for
|
||||||
|
identification since the extensions are passed in.
|
||||||
|
:type namespace: str
|
||||||
|
:param propagate_map_exceptions: Boolean controlling whether exceptions
|
||||||
|
are propagated up through the map call or whether they are logged
|
||||||
|
and then ignored
|
||||||
|
:type propagate_map_exceptions: bool
|
||||||
|
:param on_load_failure_callback: Callback function that will
|
||||||
|
be called when a entrypoint can not be loaded. The
|
||||||
|
arguments that will be provided when this is called (when
|
||||||
|
an entrypoint fails to load) are (manager, entrypoint,
|
||||||
|
exception)
|
||||||
|
:type on_load_failure_callback: function
|
||||||
|
:param verify_requirements: Use setuptools to enforce the
|
||||||
|
dependencies of the plugin(s) being loaded. Defaults to False.
|
||||||
|
:type verify_requirements: bool
|
||||||
|
:return: The manager instance, initialized for testing
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
o = cls.__new__(cls)
|
||||||
|
names = [e.name for e in extensions]
|
||||||
|
o._init_attributes(namespace, names,
|
||||||
|
propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
o._init_plugins(extensions)
|
||||||
|
return o
|
||||||
|
|
||||||
|
def _init_attributes(self, namespace, names, name_order=False,
|
||||||
|
propagate_map_exceptions=False,
|
||||||
|
on_load_failure_callback=None):
|
||||||
|
super(NamedExtensionManager, self)._init_attributes(
|
||||||
|
namespace, propagate_map_exceptions=propagate_map_exceptions,
|
||||||
|
on_load_failure_callback=on_load_failure_callback)
|
||||||
|
|
||||||
|
self._names = names
|
||||||
|
self._name_order = name_order
|
||||||
|
|
||||||
|
def _init_plugins(self, extensions):
|
||||||
|
super(NamedExtensionManager, self)._init_plugins(extensions)
|
||||||
|
|
||||||
|
if self._name_order:
|
||||||
|
self.extensions = [self[n] for n in self._names]
|
||||||
|
|
||||||
|
def _load_one_plugin(self, ep, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements):
|
||||||
|
# Check the name before going any further to prevent
|
||||||
|
# undesirable code from being loaded at all if we are not
|
||||||
|
# going to use it.
|
||||||
|
if ep.name not in self._names:
|
||||||
|
return None
|
||||||
|
return super(NamedExtensionManager, self)._load_one_plugin(
|
||||||
|
ep, invoke_on_load, invoke_args, invoke_kwds,
|
||||||
|
verify_requirements,
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue