Merge pull request #441 from jodal/feature/argparse
Switch from optparse to argparse
This commit is contained in:
commit
ddef55e0e5
@ -14,6 +14,14 @@ v0.15.0 (UNRELEASED)
|
||||
- Mopidy no longer supports Python 2.6. Currently, the only Python version
|
||||
supported by Mopidy is Python 2.7. (Fixes: :issue:`344`)
|
||||
|
||||
**Command line options**
|
||||
|
||||
- Converted from the optparse to the argparse library for handling command line
|
||||
options.
|
||||
|
||||
- :option:`mopidy --show-config` will now take into consideration any
|
||||
:option:`mopidy --option` arguments appearing later on the command line.
|
||||
|
||||
|
||||
v0.14.1 (2013-04-28)
|
||||
====================
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
@ -24,11 +23,11 @@ sys.path.insert(
|
||||
0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../')))
|
||||
|
||||
|
||||
from mopidy import ext
|
||||
from mopidy import commands, ext
|
||||
from mopidy.audio import Audio
|
||||
from mopidy import config as config_lib
|
||||
from mopidy.core import Core
|
||||
from mopidy.utils import deps, log, path, process, versioning
|
||||
from mopidy.utils import log, path, process
|
||||
|
||||
logger = logging.getLogger('mopidy.main')
|
||||
|
||||
@ -37,11 +36,13 @@ def main():
|
||||
signal.signal(signal.SIGTERM, process.exit_handler)
|
||||
signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks)
|
||||
|
||||
loop = gobject.MainLoop()
|
||||
options = parse_options()
|
||||
config_files = options.config.split(b':')
|
||||
config_overrides = options.overrides
|
||||
args = commands.parser.parse_args(args=mopidy_args)
|
||||
if args.show_config:
|
||||
commands.show_config(args)
|
||||
if args.show_deps:
|
||||
commands.show_deps()
|
||||
|
||||
loop = gobject.MainLoop()
|
||||
enabled_extensions = [] # Make sure it is defined before the finally block
|
||||
logging_initialized = False
|
||||
|
||||
@ -50,17 +51,18 @@ def main():
|
||||
|
||||
try:
|
||||
# Initial config without extensions to bootstrap logging.
|
||||
logging_config, _ = config_lib.load(config_files, [], config_overrides)
|
||||
logging_config, _ = config_lib.load(
|
||||
args.config_files, [], args.config_overrides)
|
||||
|
||||
# TODO: setup_logging needs defaults in-case config values are None
|
||||
log.setup_logging(
|
||||
logging_config, options.verbosity_level, options.save_debug_log)
|
||||
logging_config, args.verbosity_level, args.save_debug_log)
|
||||
logging_initialized = True
|
||||
|
||||
installed_extensions = ext.load_extensions()
|
||||
|
||||
config, config_errors = config_lib.load(
|
||||
config_files, installed_extensions, config_overrides)
|
||||
args.config_files, installed_extensions, args.config_overrides)
|
||||
|
||||
# Filter out disabled extensions and remove any config errors for them.
|
||||
for extension in installed_extensions:
|
||||
@ -123,78 +125,6 @@ def check_config_errors(errors):
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_config_override(option, opt, override):
|
||||
try:
|
||||
return config_lib.parse_override(override)
|
||||
except ValueError:
|
||||
raise optparse.OptionValueError(
|
||||
'option %s: must have the format section/key=value' % opt)
|
||||
|
||||
|
||||
def parse_options():
|
||||
parser = optparse.OptionParser(
|
||||
version='Mopidy %s' % versioning.get_version())
|
||||
|
||||
# Ugly extension of optparse type checking magic :/
|
||||
optparse.Option.TYPES += ('config_override',)
|
||||
optparse.Option.TYPE_CHECKER['config_override'] = check_config_override
|
||||
|
||||
parser.add_option(
|
||||
'-q', '--quiet',
|
||||
action='store_const', const=0, dest='verbosity_level',
|
||||
help='less output (warning level)')
|
||||
parser.add_option(
|
||||
'-v', '--verbose',
|
||||
action='count', default=1, dest='verbosity_level',
|
||||
help='more output (debug level)')
|
||||
parser.add_option(
|
||||
'--save-debug-log',
|
||||
action='store_true', dest='save_debug_log',
|
||||
help='save debug log to "./mopidy.log"')
|
||||
parser.add_option(
|
||||
'--show-config',
|
||||
action='callback', callback=show_config_callback,
|
||||
help='show current config')
|
||||
parser.add_option(
|
||||
'--show-deps',
|
||||
action='callback', callback=deps.show_deps_optparse_callback,
|
||||
help='show dependencies and their versions')
|
||||
parser.add_option(
|
||||
'--config',
|
||||
action='store', dest='config',
|
||||
default=b'$XDG_CONFIG_DIR/mopidy/mopidy.conf',
|
||||
help='config files to use, colon seperated, later files override')
|
||||
parser.add_option(
|
||||
'-o', '--option',
|
||||
action='append', dest='overrides', type='config_override',
|
||||
help='`section/key=value` values to override config options')
|
||||
return parser.parse_args(args=mopidy_args)[0]
|
||||
|
||||
|
||||
def show_config_callback(option, opt, value, parser):
|
||||
# TODO: don't use callback for this as --config or -o set after
|
||||
# --show-config will be ignored.
|
||||
files = getattr(parser.values, 'config', b'').split(b':')
|
||||
overrides = getattr(parser.values, 'overrides', [])
|
||||
|
||||
extensions = ext.load_extensions()
|
||||
config, errors = config_lib.load(files, extensions, overrides)
|
||||
|
||||
# Clear out any config for disabled extensions.
|
||||
for extension in extensions:
|
||||
if not ext.validate_extension(extension):
|
||||
config[extension.ext_name] = {b'enabled': False}
|
||||
errors[extension.ext_name] = {
|
||||
b'enabled': b'extension disabled its self.'}
|
||||
elif not config[extension.ext_name]['enabled']:
|
||||
config[extension.ext_name] = {b'enabled': False}
|
||||
errors[extension.ext_name] = {
|
||||
b'enabled': b'extension disabled by config.'}
|
||||
|
||||
print config_lib.format(config, extensions, errors)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def check_old_locations():
|
||||
dot_mopidy_dir = path.expand_path(b'~/.mopidy')
|
||||
if os.path.isdir(dot_mopidy_dir):
|
||||
|
||||
83
mopidy/commands.py
Normal file
83
mopidy/commands.py
Normal file
@ -0,0 +1,83 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from mopidy import config as config_lib, ext
|
||||
from mopidy.utils import deps, versioning
|
||||
|
||||
|
||||
def config_files_type(value):
|
||||
return value.split(b':')
|
||||
|
||||
|
||||
def config_override_type(value):
|
||||
try:
|
||||
section, remainder = value.split(b'/', 1)
|
||||
key, value = remainder.split(b'=', 1)
|
||||
return (section.strip(), key.strip(), value.strip())
|
||||
except ValueError:
|
||||
raise argparse.ArgumentTypeError(
|
||||
'%s must have the format section/key=value' % value)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--version', action='version',
|
||||
version='Mopidy %s' % versioning.get_version())
|
||||
parser.add_argument(
|
||||
'-q', '--quiet',
|
||||
action='store_const', const=0, dest='verbosity_level',
|
||||
help='less output (warning level)')
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
action='count', default=1, dest='verbosity_level',
|
||||
help='more output (debug level)')
|
||||
parser.add_argument(
|
||||
'--save-debug-log',
|
||||
action='store_true', dest='save_debug_log',
|
||||
help='save debug log to "./mopidy.log"')
|
||||
parser.add_argument(
|
||||
'--show-config',
|
||||
action='store_true', dest='show_config',
|
||||
help='show current config')
|
||||
parser.add_argument(
|
||||
'--show-deps',
|
||||
action='store_true', dest='show_deps',
|
||||
help='show dependencies and their versions')
|
||||
parser.add_argument(
|
||||
'--config',
|
||||
action='store', dest='config_files', type=config_files_type,
|
||||
default=b'$XDG_CONFIG_DIR/mopidy/mopidy.conf',
|
||||
help='config files to use, colon seperated, later files override')
|
||||
parser.add_argument(
|
||||
'-o', '--option',
|
||||
action='append', dest='config_overrides', type=config_override_type,
|
||||
help='`section/key=value` values to override config options')
|
||||
|
||||
|
||||
def show_config(args):
|
||||
"""Prints the effective config and exits."""
|
||||
extensions = ext.load_extensions()
|
||||
config, errors = config_lib.load(
|
||||
args.config_files, extensions, args.config_overrides)
|
||||
|
||||
# Clear out any config for disabled extensions.
|
||||
for extension in extensions:
|
||||
if not ext.validate_extension(extension):
|
||||
config[extension.ext_name] = {b'enabled': False}
|
||||
errors[extension.ext_name] = {
|
||||
b'enabled': b'extension disabled its self.'}
|
||||
elif not config[extension.ext_name]['enabled']:
|
||||
config[extension.ext_name] = {b'enabled': False}
|
||||
errors[extension.ext_name] = {
|
||||
b'enabled': b'extension disabled by config.'}
|
||||
|
||||
print config_lib.format(config, extensions, errors)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def show_deps():
|
||||
"""Prints a list of all dependencies and exits."""
|
||||
print deps.format_dependency_list()
|
||||
sys.exit(0)
|
||||
@ -140,13 +140,6 @@ def _format(config, comments, schemas, display):
|
||||
return b'\n'.join(output)
|
||||
|
||||
|
||||
def parse_override(override):
|
||||
"""Parse ``section/key=value`` command line overrides"""
|
||||
section, remainder = override.split(b'/', 1)
|
||||
key, value = remainder.split(b'=', 1)
|
||||
return (section.strip(), key.strip(), value.strip())
|
||||
|
||||
|
||||
class Proxy(collections.Mapping):
|
||||
def __init__(self, data):
|
||||
self._data = data
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
@ -33,7 +33,7 @@ from mopidy.utils import log, path, versioning
|
||||
|
||||
|
||||
def main():
|
||||
options = parse_options()
|
||||
args = parse_args()
|
||||
# TODO: support config files and overrides (shared from main?)
|
||||
config_files = [b'/etc/mopidy/mopidy.conf',
|
||||
b'$XDG_CONFIG_DIR/mopidy/mopidy.conf']
|
||||
@ -43,7 +43,7 @@ def main():
|
||||
# Initial config without extensions to bootstrap logging.
|
||||
logging_config, _ = config_lib.load(config_files, [], config_overrides)
|
||||
log.setup_root_logger()
|
||||
log.setup_console_logging(logging_config, options.verbosity_level)
|
||||
log.setup_console_logging(logging_config, args.verbosity_level)
|
||||
|
||||
extensions = ext.load_extensions()
|
||||
config, errors = config_lib.load(
|
||||
@ -87,18 +87,20 @@ def main():
|
||||
logging.info('Done writing tag cache')
|
||||
|
||||
|
||||
def parse_options():
|
||||
parser = optparse.OptionParser(
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--version', action='version',
|
||||
version='Mopidy %s' % versioning.get_version())
|
||||
parser.add_option(
|
||||
parser.add_argument(
|
||||
'-q', '--quiet',
|
||||
action='store_const', const=0, dest='verbosity_level',
|
||||
help='less output (warning level)')
|
||||
parser.add_option(
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
action='count', default=1, dest='verbosity_level',
|
||||
help='more output (debug level)')
|
||||
return parser.parse_args(args=mopidy_args)[0]
|
||||
return parser.parse_args(args=mopidy_args)
|
||||
|
||||
|
||||
def translator(data):
|
||||
|
||||
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
||||
import functools
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
@ -14,17 +13,6 @@ import pkg_resources
|
||||
from . import formatting
|
||||
|
||||
|
||||
def show_deps_optparse_callback(*args):
|
||||
"""
|
||||
Prints a list of all dependencies.
|
||||
|
||||
Called by optparse when Mopidy is run with the :option:`--show-deps`
|
||||
option.
|
||||
"""
|
||||
print format_dependency_list()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def format_dependency_list(adapters=None):
|
||||
if adapters is None:
|
||||
dist_names = set([
|
||||
|
||||
44
tests/commands_test.py
Normal file
44
tests/commands_test.py
Normal file
@ -0,0 +1,44 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import unittest
|
||||
|
||||
from mopidy import commands
|
||||
|
||||
|
||||
class ConfigOverrideTypeTest(unittest.TestCase):
|
||||
def test_valid_override(self):
|
||||
expected = (b'section', b'key', b'value')
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section/key=value'))
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section/key=value '))
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section/key =value'))
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section /key=value'))
|
||||
|
||||
def test_valid_override_is_bytes(self):
|
||||
section, key, value = commands.config_override_type(
|
||||
b'section/key=value')
|
||||
self.assertIsInstance(section, bytes)
|
||||
self.assertIsInstance(key, bytes)
|
||||
self.assertIsInstance(value, bytes)
|
||||
|
||||
def test_empty_override(self):
|
||||
expected = ('section', 'key', '')
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section/key='))
|
||||
self.assertEqual(
|
||||
expected, commands.config_override_type(b'section/key= '))
|
||||
|
||||
def test_invalid_override(self):
|
||||
self.assertRaises(
|
||||
argparse.ArgumentTypeError,
|
||||
commands.config_override_type, b'section/key')
|
||||
self.assertRaises(
|
||||
argparse.ArgumentTypeError,
|
||||
commands.config_override_type, b'section=')
|
||||
self.assertRaises(
|
||||
argparse.ArgumentTypeError,
|
||||
commands.config_override_type, b'section')
|
||||
@ -106,31 +106,3 @@ class ValidateTest(unittest.TestCase):
|
||||
self.assertEqual({'foo': {'bar': 'bad'}}, errors)
|
||||
|
||||
# TODO: add more tests
|
||||
|
||||
|
||||
class ParseOverrideTest(unittest.TestCase):
|
||||
def test_valid_override(self):
|
||||
expected = (b'section', b'key', b'value')
|
||||
self.assertEqual(expected, config.parse_override(b'section/key=value'))
|
||||
self.assertEqual(
|
||||
expected, config.parse_override(b'section/key=value '))
|
||||
self.assertEqual(
|
||||
expected, config.parse_override(b'section/key =value'))
|
||||
self.assertEqual(
|
||||
expected, config.parse_override(b'section /key=value'))
|
||||
|
||||
def test_valid_override_is_bytes(self):
|
||||
section, key, value = config.parse_override(b'section/key=value')
|
||||
self.assertIsInstance(section, bytes)
|
||||
self.assertIsInstance(key, bytes)
|
||||
self.assertIsInstance(value, bytes)
|
||||
|
||||
def test_empty_override(self):
|
||||
expected = ('section', 'key', '')
|
||||
self.assertEqual(expected, config.parse_override(b'section/key='))
|
||||
self.assertEqual(expected, config.parse_override(b'section/key= '))
|
||||
|
||||
def test_invalid_override(self):
|
||||
self.assertRaises(ValueError, config.parse_override, b'section/key')
|
||||
self.assertRaises(ValueError, config.parse_override, b'section=')
|
||||
self.assertRaises(ValueError, config.parse_override, b'section')
|
||||
|
||||
Loading…
Reference in New Issue
Block a user