/usr/lib/python2.7/dist-packages/mopidy/ext.py is in mopidy 0.19.4-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | from __future__ import unicode_literals
import collections
import logging
import pkg_resources
from mopidy import config as config_lib, exceptions
logger = logging.getLogger(__name__)
class Extension(object):
"""Base class for Mopidy extensions"""
dist_name = None
"""The extension's distribution name, as registered on PyPI
Example: ``Mopidy-Soundspot``
"""
ext_name = None
"""The extension's short name, as used in setup.py and as config section
name
Example: ``soundspot``
"""
version = None
"""The extension's version
Should match the :attr:`__version__` attribute on the extension's main
Python module and the version registered on PyPI.
"""
def get_default_config(self):
"""The extension's default config as a bytestring
:returns: bytes or unicode
"""
raise NotImplementedError(
'Add at least a config section with "enabled = true"')
def get_config_schema(self):
"""The extension's config validation schema
:returns: :class:`~mopidy.config.schema.ExtensionConfigSchema`
"""
schema = config_lib.ConfigSchema(self.ext_name)
schema['enabled'] = config_lib.Boolean()
return schema
def get_command(self):
"""Command to expose to command line users running mopidy.
:returns:
Instance of a :class:`~mopidy.commands.Command` class.
"""
pass
def validate_environment(self):
"""Checks if the extension can run in the current environment
For example, this method can be used to check if all dependencies that
are needed are installed. If a problem is found, raise
:exc:`~mopidy.exceptions.ExtensionError` with a message explaining the
issue.
:raises: :exc:`~mopidy.exceptions.ExtensionError`
:returns: :class:`None`
"""
pass
def setup(self, registry):
"""
Register the extension's components in the extension :class:`Registry`.
For example, to register a backend::
def setup(self, registry):
from .backend import SoundspotBackend
registry.add('backend', SoundspotBackend)
See :class:`Registry` for a list of registry keys with a special
meaning. Mopidy will instantiate and start any classes registered under
the ``frontend`` and ``backend`` registry keys.
This method can also be used for other setup tasks not involving the
extension registry. For example, to register custom GStreamer
elements::
def setup(self, registry):
from .mixer import SoundspotMixer
gobject.type_register(SoundspotMixer)
gst.element_register(
SoundspotMixer, 'soundspotmixer', gst.RANK_MARGINAL)
:param registry: the extension registry
:type registry: :class:`Registry`
"""
raise NotImplementedError
class Registry(collections.Mapping):
"""Registry of components provided by Mopidy extensions.
Passed to the :meth:`~Extension.setup` method of all extensions. The
registry can be used like a dict of string keys and lists.
Some keys have a special meaning, including, but not limited to:
- ``backend`` is used for Mopidy backend classes.
- ``frontend`` is used for Mopidy frontend classes.
- ``local:library`` is used for Mopidy-Local libraries.
Extensions can use the registry for allow other to extend the extension
itself. For example the ``Mopidy-Local`` use the ``local:library`` key to
allow other extensions to register library providers for ``Mopidy-Local``
to use. Extensions should namespace custom keys with the extension's
:attr:`~Extension.ext_name`, e.g. ``local:foo`` or ``http:bar``.
"""
def __init__(self):
self._registry = {}
def add(self, name, cls):
"""Add a component to the registry.
Multiple classes can be registered to the same name.
"""
self._registry.setdefault(name, []).append(cls)
def __getitem__(self, name):
return self._registry.setdefault(name, [])
def __iter__(self):
return iter(self._registry)
def __len__(self):
return len(self._registry)
def load_extensions():
"""Find all installed extensions.
:returns: list of installed extensions
"""
installed_extensions = []
for entry_point in pkg_resources.iter_entry_points('mopidy.ext'):
logger.debug('Loading entry point: %s', entry_point)
extension_class = entry_point.load(require=False)
extension = extension_class()
extension.entry_point = entry_point
installed_extensions.append(extension)
logger.debug(
'Loaded extension: %s %s', extension.dist_name, extension.version)
names = (e.ext_name for e in installed_extensions)
logger.debug('Discovered extensions: %s', ', '.join(names))
return installed_extensions
def validate_extension(extension):
"""Verify extension's dependencies and environment.
:param extensions: an extension to check
:returns: if extension should be run
"""
logger.debug('Validating extension: %s', extension.ext_name)
if extension.ext_name != extension.entry_point.name:
logger.warning(
'Disabled extension %(ep)s: entry point name (%(ep)s) '
'does not match extension name (%(ext)s)',
{'ep': extension.entry_point.name, 'ext': extension.ext_name})
return False
try:
extension.entry_point.require()
except pkg_resources.DistributionNotFound as ex:
logger.info(
'Disabled extension %s: Dependency %s not found',
extension.ext_name, ex)
return False
except pkg_resources.VersionConflict as ex:
found, required = ex.args
logger.info(
'Disabled extension %s: %s required, but found %s at %s',
extension.ext_name, required, found, found.location)
return False
try:
extension.validate_environment()
except exceptions.ExtensionError as ex:
logger.info(
'Disabled extension %s: %s', extension.ext_name, ex.message)
return False
return True
|