From 8d240ea686901e78fc58de10c0634b28ce079c07 Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 19:47:41 +0200 Subject: [PATCH 1/7] Read missing local settings from stdin by default --- mopidy/utils/settings.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 01fee23d..9516b334 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -1,6 +1,7 @@ # Absolute import needed to import ~/.mopidy/settings.py and not ourselves from __future__ import absolute_import from copy import copy +import getpass import logging import os from pprint import pformat @@ -16,8 +17,23 @@ class SettingsProxy(object): self.default = self._get_settings_dict_from_module( default_settings_module) self.local = self._get_local_settings() + self._read_missing_settings_from_stdin(self.default, self.local) self.runtime = {} + def _read_missing_settings_from_stdin(self, default, local): + for setting, value in default.iteritems(): + if isinstance(value, basestring) and len(value) == 0: + local[setting] = self._read_from_stdin(setting + u': ') + + def _read_from_stdin(self, prompt): + if u'_PASSWORD' in prompt: + return (getpass.getpass(prompt) + .decode(getpass.sys.stdin.encoding, 'ignore')) + else: + sys.stdout.write(prompt) + return (sys.stdin.readline().strip() + .decode(sys.stdin.encoding, 'ignore')) + def _get_local_settings(self): dotdir = os.path.expanduser(u'~/.mopidy/') settings_file = os.path.join(dotdir, u'settings.py') From efa38d2449c6e390890ba8850fea21f147af3c89 Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:03:02 +0200 Subject: [PATCH 2/7] Read interactive settings optional by adding --interactive option --- mopidy/core.py | 9 ++++++--- mopidy/utils/settings.py | 5 +++-- tests/help_test.py | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index ca5b92a1..e8857b94 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -30,7 +30,7 @@ logger = logging.getLogger('mopidy.core') def main(): options = parse_options() setup_logging(options.verbosity_level, options.save_debug_log) - setup_settings() + setup_settings(options.interactive) setup_gobject_loop() setup_gstreamer() setup_mixer() @@ -49,6 +49,9 @@ def parse_options(): parser.add_option('--help-gst', action='store_true', dest='help_gst', help='show GStreamer help options') + parser.add_option('-i', '--interactive', + action='store_true', dest='interactive', + help='ask interactively for required settings which is missing') parser.add_option('-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') @@ -63,11 +66,11 @@ def parse_options(): help='list current settings') return parser.parse_args(args=mopidy_args)[0] -def setup_settings(): +def setup_settings(interactive): get_or_create_folder('~/.mopidy/') get_or_create_file('~/.mopidy/settings.py') try: - settings.validate() + settings.validate(interactive) except SettingsError, e: logger.error(e.message) sys.exit(1) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 9516b334..a5b3bed2 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -17,7 +17,6 @@ class SettingsProxy(object): self.default = self._get_settings_dict_from_module( default_settings_module) self.local = self._get_local_settings() - self._read_missing_settings_from_stdin(self.default, self.local) self.runtime = {} def _read_missing_settings_from_stdin(self, default, local): @@ -79,7 +78,9 @@ class SettingsProxy(object): else: super(SettingsProxy, self).__setattr__(attr, value) - def validate(self): + def validate(self, interactive): + if interactive: + self._read_missing_settings_from_stdin(self.default, self.local) if self.get_errors(): logger.error(u'Settings validation errors: %s', indent(self.get_errors_as_string())) diff --git a/tests/help_test.py b/tests/help_test.py index dccccc9c..25f534c2 100644 --- a/tests/help_test.py +++ b/tests/help_test.py @@ -14,6 +14,7 @@ class HelpTest(unittest.TestCase): self.assert_('--version' in output) self.assert_('--help' in output) self.assert_('--help-gst' in output) + self.assert_('--interactive' in output) self.assert_('--quiet' in output) self.assert_('--verbose' in output) self.assert_('--save-debug-log' in output) From ded513faed372b9df6fad80b1482408b61b10132 Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:04:05 +0200 Subject: [PATCH 3/7] Catch keyboard interrupts in all core setup methods --- mopidy/core.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index e8857b94..98575478 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -28,15 +28,15 @@ from mopidy.utils.settings import list_settings_optparse_callback logger = logging.getLogger('mopidy.core') def main(): - options = parse_options() - setup_logging(options.verbosity_level, options.save_debug_log) - setup_settings(options.interactive) - setup_gobject_loop() - setup_gstreamer() - setup_mixer() - setup_backend() - setup_frontends() try: + options = parse_options() + setup_logging(options.verbosity_level, options.save_debug_log) + setup_settings(options.interactive) + setup_gobject_loop() + setup_gstreamer() + setup_mixer() + setup_backend() + setup_frontends() while ActorRegistry.get_all(): time.sleep(1) logger.info(u'No actors left. Exiting...') From c31db049791bf4fbffc4882d190ea4f9d613f1c4 Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:08:50 +0200 Subject: [PATCH 4/7] Move private methods to be closer it's caller --- mopidy/utils/settings.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index a5b3bed2..73268345 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -19,20 +19,6 @@ class SettingsProxy(object): self.local = self._get_local_settings() self.runtime = {} - def _read_missing_settings_from_stdin(self, default, local): - for setting, value in default.iteritems(): - if isinstance(value, basestring) and len(value) == 0: - local[setting] = self._read_from_stdin(setting + u': ') - - def _read_from_stdin(self, prompt): - if u'_PASSWORD' in prompt: - return (getpass.getpass(prompt) - .decode(getpass.sys.stdin.encoding, 'ignore')) - else: - sys.stdout.write(prompt) - return (sys.stdin.readline().strip() - .decode(sys.stdin.encoding, 'ignore')) - def _get_local_settings(self): dotdir = os.path.expanduser(u'~/.mopidy/') settings_file = os.path.join(dotdir, u'settings.py') @@ -86,6 +72,20 @@ class SettingsProxy(object): indent(self.get_errors_as_string())) raise SettingsError(u'Settings validation failed.') + def _read_missing_settings_from_stdin(self, default, local): + for setting, value in default.iteritems(): + if isinstance(value, basestring) and len(value) == 0: + local[setting] = self._read_from_stdin(setting + u': ') + + def _read_from_stdin(self, prompt): + if u'_PASSWORD' in prompt: + return (getpass.getpass(prompt) + .decode(getpass.sys.stdin.encoding, 'ignore')) + else: + sys.stdout.write(prompt) + return (sys.stdin.readline().strip() + .decode(sys.stdin.encoding, 'ignore')) + def get_errors(self): return validate_settings(self.default, self.local) From 33e70de66147d83702b7382a4a617a0e2e4a2eac Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:28:38 +0200 Subject: [PATCH 5/7] Test interactive input --- tests/utils/settings_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/utils/settings_test.py b/tests/utils/settings_test.py index 748eae85..d1481ce5 100644 --- a/tests/utils/settings_test.py +++ b/tests/utils/settings_test.py @@ -149,6 +149,12 @@ class SettingsProxyTest(unittest.TestCase): actual = self.settings.TEST self.assertEqual(actual, './test') + def test_interactive_input_of_missing_defaults(self): + self.settings.default['TEST'] = '' + interactive_input = 'input' + self.settings._read_from_stdin = lambda _: interactive_input + self.settings.validate(interactive=True) + self.assertEqual(interactive_input, self.settings.TEST) class FormatSettingListTest(unittest.TestCase): def setUp(self): From 5e0a85c1b6195949c1cd9953db689d0a81a2326d Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:38:52 +0200 Subject: [PATCH 6/7] Get encoding from sys module directly instead of getpass.sys --- mopidy/utils/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 73268345..a10b3a78 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -80,7 +80,7 @@ class SettingsProxy(object): def _read_from_stdin(self, prompt): if u'_PASSWORD' in prompt: return (getpass.getpass(prompt) - .decode(getpass.sys.stdin.encoding, 'ignore')) + .decode(sys.stdin.encoding, 'ignore')) else: sys.stdout.write(prompt) return (sys.stdin.readline().strip() From 32915b6832f2eed418d370944ae99e041f75099b Mon Sep 17 00:00:00 2001 From: Johannes Knutsen Date: Thu, 9 Jun 2011 20:47:20 +0200 Subject: [PATCH 7/7] Add --interactive feature to changelog --- docs/changes.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changes.rst b/docs/changes.rst index 4b6f74ca..2c240bfa 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -70,6 +70,9 @@ Please note that 0.5.0 requires some updated dependencies, as listed under - Improve :option:`--list-settings` output. (Fixes: :issue:`91`) + - Added :option:`--interactive` for reading missing local settings from + ``stdin``. (Fixes: :issue:`96`) + - Tag cache generator: - Made it possible to abort :command:`mopidy-scan` with CTRL+C.