From fd2c56053b6ddadb876b083677e5d11a22ebceb8 Mon Sep 17 00:00:00 2001 From: Samantha Baldwin Date: Wed, 7 Mar 2018 08:39:29 -0500 Subject: [PATCH] read command parameters from config sections (#240) * read command parameters from config sections * README: update config file documentation * README: config example type INI, add comma * README: clearer and better spelled wording * README: fix 'delineated' typo --- README.md | 51 ++++++++++++++++++---------------- whipper/command/basecommand.py | 25 +++++++++++++---- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 3f65809..3dde670 100644 --- a/README.md +++ b/README.md @@ -157,42 +157,45 @@ The simplest way to get started making accurate rips is: ## Configuration file documentation -The configuration file is stored according to the [XDG Base Directory Specification]( -http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) -when possible. +The configuration file is stored in +`$XDG_CONFIG_HOME/whipper/whipper.conf`, or +`$HOME/.config/whipper/whipper.conf` if `$XDG_CONFIG_HOME` is undefined. -It lives in `$XDG_CONFIG_HOME/whipper/whipper.conf` (or `$HOME/.config/whipper/whipper.conf`). +See [XDG Base Directory +Specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) +and [ConfigParser](https://docs.python.org/2/library/configparser.html). -The configuration file follows python's [ConfigParser](https://docs.python.org/2/library/configparser.html) syntax. +The configuration file consists of newline-delineated `[sections]` +containing `key = value` pairs. The sections `[main]` and +`[musicbrainz]` are special config sections for options not accessible +from the command line interface. Sections beginning with `drive` are +written by whipper; certain values should not be edited. -The possible sections are: +Example configuration demonstrating all `[main]` and `[musicbrainz]` +options: -- Main section: `[main]` - - `path_filter_fat`: whether to filter path components for FAT file systems - - `path_filter_special`: whether to filter path components for special characters - -- MusicBrainz section: `[musicbrainz]` - - `server`: the MusicBrainz server to connect to, in `host:[port]` format. Defaults to `musicbrainz.org`. +```INI +[main] +path_filter_fat = True ; replace FAT file system unsafe characters in filenames with _ +path_filter_special = False ; replace special characters in filenames with _ -- Drive section: `[drive:IDENTIFIER]`, one for each configured drive. All these values are probed by whipper and should not be edited by hand. - - `defeats_cache`: whether this drive can defeat the audio cache - - `read_offset`: the read offset of the drive +[musicbrainz] +server = musicbrainz.org:80 ; use musicbrainz server at host[:port] -- Rip command section: `[rip.COMMAND.SUBCOMMAND]`. Can be used to change the command options default values. - **Please note that this feature is currently broken (being this way since [PR #122](https://github.com/JoeLametta/whipper/pull/92) / whipper [v0.4.1](https://github.com/JoeLametta/whipper/releases/tag/v0.4.1)).** +[drive:HL-20] +defeats_cache = True ; whether the drive is capable of defeating the audio cache +read_offset = 6 ; drive read offset in positive/negative frames (no leading +) +# do not edit the values 'vendor', 'model', and 'release'; they are used by whipper to match the drive -Example section to configure `whipper cd rip` defaults: - -```Python -[rip.cd.rip] +# command line defaults for `whipper cd rip` +[whipper.cd.rip] unknown = True output_directory = ~/My Music -track_template = new/%%A/%%y - %%d/%%t - %%n +track_template = new/%%A/%%y - %%d/%%t - %%n ; note: the format char '%' must be represented '%%' disc_template = %(track_template)s +# ... ``` -Note: to get a literal `%` character it must be doubled. - ## Backward incompatible changes - Rely on `cd-paranoia` (`libcdio-cdparanoia`) instead of `cdparanoia` (Xiph): changed dependency ([PR #213](https://github.com/JoeLametta/whipper/pull/213) / whipper [v0.6.0](https://github.com/JoeLametta/whipper/releases/tag/v0.6.0)) diff --git a/whipper/command/basecommand.py b/whipper/command/basecommand.py index 379a23b..4a81af2 100644 --- a/whipper/command/basecommand.py +++ b/whipper/command/basecommand.py @@ -5,7 +5,7 @@ import argparse import os import sys -from whipper.common import drive +from whipper.common import config, drive import logging logger = logging.getLogger(__name__) @@ -27,11 +27,13 @@ logger = logging.getLogger(__name__) class BaseCommand(): """ - A base command class for whipper commands. + Register and handle whipper command arguments with ArgumentParser. - Creates an argparse.ArgumentParser. - Override add_arguments() and handle_arguments() to register - and process arguments before & after argparse.parse_args(). + Register arguments by overriding `add_arguments()` and modifying + `self.parser`. Option defaults are read from the dot-separated + `prog_name` section of the config file (e.g., 'whipper cd rip' + options are read from '[whipper.cd.rip]'). Runs + `argparse.parse_args()` then calls `handle_arguments()`. Provides self.epilog() formatting command for argparse. @@ -57,6 +59,19 @@ class BaseCommand(): self.init_parser() self.add_arguments() + config_section = prog_name.replace(' ', '.') + defaults = {} + for action in self.parser._actions: + val = None + if isinstance(action, argparse._StoreAction): + val = config.Config().get(config_section, action.dest) + elif isinstance(action, (argparse._StoreTrueAction, + argparse._StoreFalseAction)): + val = config.Config().getboolean(config_section, action.dest) + if val is not None: + defaults[action.dest] = val + self.parser.set_defaults(**defaults) + if hasattr(self, 'subcommands'): self.parser.add_argument('remainder', nargs=argparse.REMAINDER,