Merge pull request #167 from jodal/feature/list-deps

Add --list-deps option
This commit is contained in:
Thomas Adamcik 2012-08-31 15:53:50 -07:00
commit fc4dcc3529
4 changed files with 314 additions and 0 deletions

View File

@ -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)
===================

View File

@ -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
View 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
View 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'])