mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-25 08:55:50 +00:00
Merge CliError into UserError
This commit is contained in:
parent
9e8b5f2dad
commit
be4baba19e
6 changed files with 56 additions and 50 deletions
|
|
@ -4,7 +4,7 @@ from textwrap import dedent
|
|||
import pytest
|
||||
|
||||
import vdirsyncer.cli.utils # noqa
|
||||
from vdirsyncer import cli
|
||||
from vdirsyncer import cli, exceptions
|
||||
from vdirsyncer.cli.config import parse_config_value, \
|
||||
read_config as _read_config
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ def test_storage_instance_from_config(monkeypatch):
|
|||
|
||||
|
||||
def test_missing_general_section(read_config):
|
||||
with pytest.raises(cli.CliError) as excinfo:
|
||||
with pytest.raises(exceptions.UserError) as excinfo:
|
||||
read_config(u'''
|
||||
[pair my_pair]
|
||||
a = my_a
|
||||
|
|
@ -87,17 +87,17 @@ def test_missing_general_section(read_config):
|
|||
fileext = .txt
|
||||
''')
|
||||
|
||||
assert 'Invalid general section.' in excinfo.value.msg
|
||||
assert 'Invalid general section.' in str(excinfo.value)
|
||||
|
||||
|
||||
def test_wrong_general_section(read_config):
|
||||
with pytest.raises(cli.CliError) as excinfo:
|
||||
with pytest.raises(exceptions.UserError) as excinfo:
|
||||
read_config(u'''
|
||||
[general]
|
||||
wrong = true
|
||||
''')
|
||||
|
||||
assert 'Invalid general section.' in excinfo.value.msg
|
||||
assert 'Invalid general section.' in str(excinfo.value)
|
||||
assert excinfo.value.problems == [
|
||||
'general section doesn\'t take the parameters: wrong',
|
||||
'general section is missing the parameters: status_path'
|
||||
|
|
@ -112,7 +112,7 @@ def test_invalid_storage_name():
|
|||
[storage foo.bar]
|
||||
'''))
|
||||
|
||||
with pytest.raises(cli.CliError) as excinfo:
|
||||
with pytest.raises(exceptions.UserError) as excinfo:
|
||||
_read_config(f)
|
||||
|
||||
assert 'invalid characters' in str(excinfo.value).lower()
|
||||
|
|
@ -169,7 +169,7 @@ def test_invalid_collections_arg():
|
|||
fileext = .txt
|
||||
'''))
|
||||
|
||||
with pytest.raises(cli.utils.CliError) as excinfo:
|
||||
with pytest.raises(exceptions.UserError) as excinfo:
|
||||
_read_config(f)
|
||||
|
||||
assert (
|
||||
|
|
|
|||
|
|
@ -24,21 +24,6 @@ class AppContext(object):
|
|||
pass_context = click.make_pass_decorator(AppContext, ensure=True)
|
||||
|
||||
|
||||
class CliError(RuntimeError):
|
||||
def __init__(self, msg, problems=None):
|
||||
self.msg = msg
|
||||
self.problems = problems
|
||||
RuntimeError.__init__(self, msg)
|
||||
|
||||
def __str__(self):
|
||||
msg = self.msg
|
||||
li = u'\n - '
|
||||
for problem in self.problems or ():
|
||||
msg += u'{}{}'.format(li, problem)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
def catch_errors(f):
|
||||
@functools.wraps(f)
|
||||
def inner(*a, **kw):
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import os
|
|||
import string
|
||||
from itertools import chain
|
||||
|
||||
from . import CliError, cli_logger
|
||||
from . import cli_logger
|
||||
from .fetchparams import expand_fetch_params
|
||||
from .. import PROJECT_HOME
|
||||
from .. import PROJECT_HOME, exceptions
|
||||
from ..utils import cached_property, expand_path
|
||||
from ..utils.compat import text_type
|
||||
|
||||
|
|
@ -23,10 +23,10 @@ def validate_section_name(name, section_type):
|
|||
invalid = set(name) - SECTION_NAME_CHARS
|
||||
if invalid:
|
||||
chars_display = ''.join(sorted(SECTION_NAME_CHARS))
|
||||
raise CliError('The {}-section "{}" contains invalid characters. Only '
|
||||
'the following characters are allowed for storage and '
|
||||
'pair names:\n{}'.format(section_type, name,
|
||||
chars_display))
|
||||
raise exceptions.UserError(
|
||||
'The {}-section "{}" contains invalid characters. Only '
|
||||
'the following characters are allowed for storage and '
|
||||
'pair names:\n{}'.format(section_type, name, chars_display))
|
||||
|
||||
|
||||
def _validate_general_section(general_config):
|
||||
|
|
@ -48,9 +48,10 @@ def _validate_general_section(general_config):
|
|||
.format(u', '.join(missing)))
|
||||
|
||||
if problems:
|
||||
raise CliError(u'Invalid general section. Copy the example '
|
||||
u'config from the repository and edit it: {}'
|
||||
.format(PROJECT_HOME), problems=problems)
|
||||
raise exceptions.UserError(
|
||||
u'Invalid general section. Copy the example '
|
||||
u'config from the repository and edit it: {}'
|
||||
.format(PROJECT_HOME), problems=problems)
|
||||
|
||||
|
||||
def _validate_pair_section(pair_config):
|
||||
|
|
@ -77,8 +78,10 @@ def load_config():
|
|||
with open(fname) as f:
|
||||
general, pairs, storages = read_config(f)
|
||||
except Exception as e:
|
||||
raise CliError('Error during reading config {}: {}'
|
||||
.format(fname, e))
|
||||
raise exceptions.UserError(
|
||||
'Error during reading config {}: {}'
|
||||
.format(fname, e)
|
||||
)
|
||||
|
||||
return Config(general, pairs, storages)
|
||||
|
||||
|
|
@ -105,7 +108,8 @@ def read_config(f):
|
|||
|
||||
def handle_general(_, options):
|
||||
if general:
|
||||
raise CliError('More than one general section in config file.')
|
||||
raise exceptions.UserError(
|
||||
'More than one general section in config file.')
|
||||
general.update(options)
|
||||
|
||||
def bad_section(name, options):
|
||||
|
|
@ -125,7 +129,8 @@ def read_config(f):
|
|||
f = handlers.get(section_type, bad_section)
|
||||
f(name, get_options(section))
|
||||
except ValueError as e:
|
||||
raise CliError('Section `{}`: {}'.format(section, str(e)))
|
||||
raise exceptions.UserError(
|
||||
'Section `{}`: {}'.format(section, str(e)))
|
||||
|
||||
_validate_general_section(general)
|
||||
if getattr(f, 'name', None):
|
||||
|
|
@ -189,7 +194,7 @@ class Config(object):
|
|||
args = self.storages[storage_name]
|
||||
except KeyError:
|
||||
pair_pref = 'Pair {}: '.format(pair_name) if pair_name else ''
|
||||
raise CliError(
|
||||
raise exceptions.UserError(
|
||||
'{}Storage {!r} not found. '
|
||||
'These are the configured storages: {}'
|
||||
.format(pair_pref, storage_name, list(self.storages))
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import functools
|
|||
import json
|
||||
|
||||
from .config import CollectionConfig
|
||||
from .utils import CliError, JobFailed, cli_logger, coerce_native, \
|
||||
from .utils import JobFailed, cli_logger, coerce_native, \
|
||||
collections_for_pair, get_status_name, handle_cli_error, load_status, \
|
||||
save_status, storage_class_from_config, storage_instance_from_config
|
||||
|
||||
from .. import exceptions
|
||||
from ..sync import sync
|
||||
from ..utils.compat import to_unicode
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ def prepare_pair(wq, pair_name, collections, config, callback, **kwargs):
|
|||
try:
|
||||
config_a, config_b = all_collections[collection_name]
|
||||
except KeyError:
|
||||
raise CliError(
|
||||
raise exceptions.UserError(
|
||||
'Pair {}: Collection {} not found. These are the '
|
||||
'configured collections:\n{}'
|
||||
.format(pair_name,
|
||||
|
|
@ -98,8 +99,10 @@ def repair_collection(config, collection):
|
|||
if config['collection'] == collection:
|
||||
break
|
||||
else:
|
||||
raise CliError('Couldn\'t find collection {} for storage {}.'
|
||||
.format(collection, storage_name))
|
||||
raise exceptions.UserError(
|
||||
'Couldn\'t find collection {} for storage {}.'
|
||||
.format(collection, storage_name)
|
||||
)
|
||||
|
||||
config['type'] = storage_type
|
||||
storage = storage_instance_from_config(config)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import click
|
|||
|
||||
import click_threading
|
||||
|
||||
from . import CliError, cli_logger
|
||||
from . import cli_logger
|
||||
from .. import DOCS_HOME, exceptions
|
||||
from ..sync import IdentConflict, StorageEmpty, SyncConflict
|
||||
from ..utils import expand_path, get_class_init_args
|
||||
|
|
@ -78,7 +78,7 @@ def handle_cli_error(status_name=None):
|
|||
|
||||
try:
|
||||
raise
|
||||
except (CliError, exceptions.UserError) as e:
|
||||
except exceptions.UserError as e:
|
||||
cli_logger.critical(e)
|
||||
except StorageEmpty as e:
|
||||
cli_logger.error(
|
||||
|
|
@ -243,10 +243,11 @@ def _handle_collection_not_found(config, collection, e=None):
|
|||
except NotImplementedError as e:
|
||||
cli_logger.error(e)
|
||||
|
||||
raise CliError('Unable to find or create collection "{collection}" for '
|
||||
'storage "{storage}". Please create the collection '
|
||||
'yourself.'.format(collection=collection,
|
||||
storage=storage_name))
|
||||
raise exceptions.UserError(
|
||||
'Unable to find or create collection "{collection}" for '
|
||||
'storage "{storage}". Please create the collection '
|
||||
'yourself.'.format(collection=collection,
|
||||
storage=storage_name))
|
||||
|
||||
|
||||
def _collections_for_pair_impl(status_path, pair):
|
||||
|
|
@ -341,7 +342,8 @@ def storage_class_from_config(config):
|
|||
try:
|
||||
cls = storage_names[storage_name]
|
||||
except KeyError:
|
||||
raise CliError('Unknown storage type: {}'.format(storage_name))
|
||||
raise exceptions.UserError(
|
||||
'Unknown storage type: {}'.format(storage_name))
|
||||
return cls, config
|
||||
|
||||
|
||||
|
|
@ -368,7 +370,7 @@ def storage_instance_from_config(config, create=True):
|
|||
|
||||
def handle_storage_init_error(cls, config):
|
||||
e = sys.exc_info()[1]
|
||||
if isinstance(e, (click.Abort, CliError, KeyboardInterrupt)):
|
||||
if isinstance(e, (click.Abort, exceptions.UserError, KeyboardInterrupt)):
|
||||
raise
|
||||
|
||||
all, required = get_class_init_args(cls)
|
||||
|
|
@ -393,8 +395,10 @@ def handle_storage_init_error(cls, config):
|
|||
cli_logger.exception('')
|
||||
problems.append(str(e))
|
||||
|
||||
raise CliError(u'Failed to initialize {}'.format(config['instance_name']),
|
||||
problems=problems)
|
||||
raise exceptions.UserError(
|
||||
u'Failed to initialize {}'.format(config['instance_name']),
|
||||
problems=problems
|
||||
)
|
||||
|
||||
|
||||
class WorkerQueue(object):
|
||||
|
|
|
|||
|
|
@ -21,6 +21,15 @@ class UserError(Error, ValueError):
|
|||
'''Wrapper exception to be used to signify the traceback should not be
|
||||
shown to the user.'''
|
||||
|
||||
problems = None
|
||||
|
||||
def __str__(self):
|
||||
msg = Error.__str__(self)
|
||||
for problem in self.problems or ():
|
||||
msg += u'\n - {}'.format(problem)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class CollectionNotFound(Error):
|
||||
'''Collection not found'''
|
||||
|
|
|
|||
Loading…
Reference in a new issue