Merge pull request #167 from jodal/feature/list-deps
Add --list-deps option
This commit is contained in:
commit
fc4dcc3529
@ -18,6 +18,10 @@ v0.8 (in development)
|
||||
Track position and CPID was intermixed, so it would cause a crash if a CPID
|
||||
matching the track position didn't exist. (Fixes: :issue:`162`)
|
||||
|
||||
- Added :option:`--list-deps` option to :cmd:`mopidy` command that lists
|
||||
required and optional dependencies, their current versions, and some other
|
||||
information useful for debugging. (Fixes: :issue:`74`)
|
||||
|
||||
|
||||
v0.7.3 (2012-08-11)
|
||||
===================
|
||||
|
||||
@ -22,6 +22,7 @@ from mopidy import (get_version, settings, OptionalDependencyError,
|
||||
SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE)
|
||||
from mopidy.gstreamer import GStreamer
|
||||
from mopidy.utils import get_class
|
||||
from mopidy.utils.deps import list_deps_optparse_callback
|
||||
from mopidy.utils.log import setup_logging
|
||||
from mopidy.utils.path import get_or_create_folder, get_or_create_file
|
||||
from mopidy.utils.process import (exit_handler, stop_remaining_actors,
|
||||
@ -77,6 +78,9 @@ def parse_options():
|
||||
parser.add_option('--list-settings',
|
||||
action='callback', callback=list_settings_optparse_callback,
|
||||
help='list current settings')
|
||||
parser.add_option('--list-deps',
|
||||
action='callback', callback=list_deps_optparse_callback,
|
||||
help='list dependencies and their versions')
|
||||
return parser.parse_args(args=mopidy_args)[0]
|
||||
|
||||
def check_old_folders():
|
||||
|
||||
193
mopidy/utils/deps.py
Normal file
193
mopidy/utils/deps.py
Normal file
@ -0,0 +1,193 @@
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst
|
||||
|
||||
import pykka
|
||||
|
||||
from mopidy.utils.log import indent
|
||||
|
||||
|
||||
def list_deps_optparse_callback(*args):
|
||||
"""
|
||||
Prints a list of all dependencies.
|
||||
|
||||
Called by optparse when Mopidy is run with the :option:`--list-deps`
|
||||
option.
|
||||
"""
|
||||
print format_dependency_list()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def format_dependency_list(adapters=None):
|
||||
if adapters is None:
|
||||
adapters = [
|
||||
platform_info,
|
||||
python_info,
|
||||
gstreamer_info,
|
||||
pykka_info,
|
||||
pyspotify_info,
|
||||
pylast_info,
|
||||
dbus_info,
|
||||
serial_info,
|
||||
]
|
||||
|
||||
lines = []
|
||||
for adapter in adapters:
|
||||
dep_info = adapter()
|
||||
lines.append('%(name)s: %(version)s' % {
|
||||
'name': dep_info['name'],
|
||||
'version': dep_info.get('version', 'not found'),
|
||||
})
|
||||
if 'path' in dep_info:
|
||||
lines.append(' Imported from: %s' % (
|
||||
os.path.dirname(dep_info['path'])))
|
||||
if 'other' in dep_info:
|
||||
lines.append(' Other: %s' % (
|
||||
indent(dep_info['other'])),)
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def platform_info():
|
||||
return {
|
||||
'name': 'Platform',
|
||||
'version': platform.platform(),
|
||||
}
|
||||
|
||||
|
||||
def python_info():
|
||||
return {
|
||||
'name': 'Python',
|
||||
'version': '%s %s' % (platform.python_implementation(),
|
||||
platform.python_version()),
|
||||
'path': platform.__file__,
|
||||
}
|
||||
|
||||
|
||||
def gstreamer_info():
|
||||
other = []
|
||||
other.append('Python wrapper: gst-python %s' % (
|
||||
'.'.join(map(str, gst.get_pygst_version()))))
|
||||
other.append('Relevant elements:')
|
||||
for name, status in _gstreamer_check_elements():
|
||||
other.append(' %s: %s' % (name, 'OK' if status else 'not found'))
|
||||
return {
|
||||
'name': 'Gstreamer',
|
||||
'version': '.'.join(map(str, gst.get_gst_version())),
|
||||
'path': gst.__file__,
|
||||
'other': '\n'.join(other),
|
||||
}
|
||||
|
||||
|
||||
def _gstreamer_check_elements():
|
||||
elements_to_check = [
|
||||
# Core playback
|
||||
'uridecodebin',
|
||||
|
||||
# External HTTP streams
|
||||
'souphttpsrc',
|
||||
|
||||
# Spotify
|
||||
'appsrc',
|
||||
|
||||
# Mixers and sinks
|
||||
'alsamixer',
|
||||
'alsasink',
|
||||
'ossmixer',
|
||||
'osssink',
|
||||
'oss4mixer',
|
||||
'oss4sink',
|
||||
'pulsemixer',
|
||||
'pulsesink',
|
||||
|
||||
# MP3 encoding and decoding
|
||||
'mp3parse',
|
||||
'mad',
|
||||
'id3demux',
|
||||
'id3v2mux',
|
||||
'lame',
|
||||
|
||||
# Ogg Vorbis encoding and decoding
|
||||
'vorbisdec',
|
||||
'vorbisenc',
|
||||
'vorbisparse',
|
||||
'oggdemux',
|
||||
'oggmux',
|
||||
'oggparse',
|
||||
|
||||
# Flac decoding
|
||||
'flacdec',
|
||||
'flacparse',
|
||||
|
||||
# Shoutcast output
|
||||
'shout2send',
|
||||
]
|
||||
known_elements = [factory.get_name() for factory in
|
||||
gst.registry_get_default().get_feature_list(gst.TYPE_ELEMENT_FACTORY)]
|
||||
return [(element, element in known_elements) for element in elements_to_check]
|
||||
|
||||
|
||||
def pykka_info():
|
||||
if hasattr(pykka, '__version__'):
|
||||
# Pykka >= 0.14
|
||||
version = pykka.__version__
|
||||
else:
|
||||
# Pykka < 0.14
|
||||
version = pykka.get_version()
|
||||
return {
|
||||
'name': 'Pykka',
|
||||
'version': version,
|
||||
'path': pykka.__file__,
|
||||
}
|
||||
|
||||
|
||||
def pyspotify_info():
|
||||
dep_info = {'name': 'pyspotify'}
|
||||
try:
|
||||
import spotify
|
||||
if hasattr(spotify, '__version__'):
|
||||
dep_info['version'] = spotify.__version__
|
||||
else:
|
||||
dep_info['version'] = '< 1.3'
|
||||
dep_info['path'] = spotify.__file__
|
||||
dep_info['other'] = 'Built for libspotify API version %d' % (
|
||||
spotify.api_version,)
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def pylast_info():
|
||||
dep_info = {'name': 'pylast'}
|
||||
try:
|
||||
import pylast
|
||||
dep_info['version'] = pylast.__version__
|
||||
dep_info['path'] = pylast.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def dbus_info():
|
||||
dep_info = {'name': 'dbus-python'}
|
||||
try:
|
||||
import dbus
|
||||
dep_info['version'] = dbus.__version__
|
||||
dep_info['path'] = dbus.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
|
||||
|
||||
def serial_info():
|
||||
dep_info = {'name': 'pyserial'}
|
||||
try:
|
||||
import serial
|
||||
dep_info['version'] = serial.VERSION
|
||||
dep_info['path'] = serial.__file__
|
||||
except ImportError:
|
||||
pass
|
||||
return dep_info
|
||||
113
tests/utils/deps_test.py
Normal file
113
tests/utils/deps_test.py
Normal file
@ -0,0 +1,113 @@
|
||||
import platform
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst
|
||||
import pykka
|
||||
|
||||
try:
|
||||
import dbus
|
||||
except ImportError:
|
||||
dbus = False
|
||||
|
||||
try:
|
||||
import pylast
|
||||
except ImportError:
|
||||
pylast = False
|
||||
|
||||
try:
|
||||
import serial
|
||||
except ImportError:
|
||||
serial = False
|
||||
|
||||
try:
|
||||
import spotify
|
||||
except ImportError:
|
||||
spotify = False
|
||||
|
||||
from mopidy.utils import deps
|
||||
|
||||
from tests import unittest
|
||||
|
||||
|
||||
class DepsTest(unittest.TestCase):
|
||||
def test_format_dependency_list(self):
|
||||
adapters = [
|
||||
lambda: dict(name='Python', version='FooPython 2.7.3'),
|
||||
lambda: dict(name='Platform', version='Loonix 4.0.1'),
|
||||
lambda: dict(name='Pykka', path='/foo/bar/baz.py', other='Quux')
|
||||
]
|
||||
|
||||
result = deps.format_dependency_list(adapters)
|
||||
|
||||
self.assertIn('Python: FooPython 2.7.3', result)
|
||||
self.assertIn('Platform: Loonix 4.0.1', result)
|
||||
self.assertIn('Pykka: not found', result)
|
||||
self.assertIn('Imported from: /foo/bar', result)
|
||||
self.assertNotIn('/baz.py', result)
|
||||
self.assertIn('Quux', result)
|
||||
|
||||
def test_platform_info(self):
|
||||
result = deps.platform_info()
|
||||
|
||||
self.assertEquals('Platform', result['name'])
|
||||
self.assertIn(platform.platform(), result['version'])
|
||||
|
||||
def test_python_info(self):
|
||||
result = deps.python_info()
|
||||
|
||||
self.assertEquals('Python', result['name'])
|
||||
self.assertIn(platform.python_implementation(), result['version'])
|
||||
self.assertIn(platform.python_version(), result['version'])
|
||||
self.assertIn('python', result['path'])
|
||||
|
||||
def test_gstreamer_info(self):
|
||||
result = deps.gstreamer_info()
|
||||
|
||||
self.assertEquals('Gstreamer', result['name'])
|
||||
self.assertEquals('.'.join(map(str, gst.get_gst_version())), result['version'])
|
||||
self.assertIn('gst', result['path'])
|
||||
self.assertIn('Python wrapper: gst-python', result['other'])
|
||||
self.assertIn('.'.join(map(str, gst.get_pygst_version())), result['other'])
|
||||
self.assertIn('Relevant elements:', result['other'])
|
||||
|
||||
def test_pykka_info(self):
|
||||
result = deps.pykka_info()
|
||||
|
||||
self.assertEquals('Pykka', result['name'])
|
||||
self.assertEquals(pykka.__version__, result['version'])
|
||||
self.assertIn('pykka', result['path'])
|
||||
|
||||
@unittest.skipUnless(spotify, 'pyspotify not found')
|
||||
def test_pyspotify_info(self):
|
||||
result = deps.pyspotify_info()
|
||||
|
||||
self.assertEquals('pyspotify', result['name'])
|
||||
self.assertEquals(spotify.__version__, result['version'])
|
||||
self.assertIn('spotify', result['path'])
|
||||
self.assertIn('Built for libspotify API version', result['other'])
|
||||
self.assertIn(str(spotify.api_version), result['other'])
|
||||
|
||||
@unittest.skipUnless(pylast, 'pylast not found')
|
||||
def test_pylast_info(self):
|
||||
result = deps.pylast_info()
|
||||
|
||||
self.assertEquals('pylast', result['name'])
|
||||
self.assertEquals(pylast.__version__, result['version'])
|
||||
self.assertIn('pylast', result['path'])
|
||||
|
||||
@unittest.skipUnless(dbus, 'dbus not found')
|
||||
def test_dbus_info(self):
|
||||
result = deps.dbus_info()
|
||||
|
||||
self.assertEquals('dbus-python', result['name'])
|
||||
self.assertEquals(dbus.__version__, result['version'])
|
||||
self.assertIn('dbus', result['path'])
|
||||
|
||||
@unittest.skipUnless(serial, 'serial not found')
|
||||
def test_serial_info(self):
|
||||
result = deps.serial_info()
|
||||
|
||||
self.assertEquals('pyserial', result['name'])
|
||||
self.assertEquals(serial.VERSION, result['version'])
|
||||
self.assertIn('serial', result['path'])
|
||||
Loading…
Reference in New Issue
Block a user