mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-29 09:35:50 +00:00
Move config parsing into cli module
This commit is contained in:
parent
6ef330aac5
commit
cdb25d61ec
4 changed files with 111 additions and 106 deletions
|
|
@ -435,3 +435,47 @@ def test_invalid_collections_arg(tmpdir, runner):
|
|||
'Section `pair foobar`: `collections` parameter must be a list of '
|
||||
'collection names (strings!) or `null`.'
|
||||
)
|
||||
|
||||
|
||||
def test_parse_config_value():
|
||||
x = cli.utils.parse_config_value
|
||||
with pytest.raises(ValueError):
|
||||
x('123 # comment!')
|
||||
|
||||
assert x('"123 # comment!"') == '123 # comment!'
|
||||
assert x('True') is True
|
||||
assert x('False') is False
|
||||
assert x('Yes') is True
|
||||
assert x('3.14') == 3.14
|
||||
assert x('') == ''
|
||||
assert x('""') == ''
|
||||
|
||||
|
||||
def test_parse_options():
|
||||
o = {
|
||||
'foo': 'yes',
|
||||
'hah': 'true',
|
||||
'bar': '',
|
||||
'baz': 'whatever',
|
||||
'bam': '123',
|
||||
'asd': 'off'
|
||||
}
|
||||
|
||||
a = dict(cli.utils.parse_options(o.items()))
|
||||
|
||||
expected = {
|
||||
'foo': True,
|
||||
'hah': True,
|
||||
'bar': '',
|
||||
'baz': 'whatever',
|
||||
'bam': 123,
|
||||
'asd': False
|
||||
}
|
||||
|
||||
assert a == expected
|
||||
|
||||
for key in a:
|
||||
# Yes, we want a very strong typecheck here, because we actually have
|
||||
# to differentiate between bool and int, and in Python 2, bool is a
|
||||
# subclass of int.
|
||||
assert type(a[key]) is type(expected[key]) # noqa
|
||||
|
|
|
|||
|
|
@ -7,28 +7,30 @@
|
|||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import click
|
||||
import pytest
|
||||
|
||||
from click.testing import CliRunner
|
||||
import os
|
||||
import stat
|
||||
|
||||
import click
|
||||
from click.testing import CliRunner
|
||||
|
||||
import pytest
|
||||
|
||||
import requests
|
||||
|
||||
import vdirsyncer.utils as utils
|
||||
import vdirsyncer.doubleclick as doubleclick
|
||||
from vdirsyncer.utils.vobject import split_collection
|
||||
import vdirsyncer.utils as utils
|
||||
|
||||
from .. import blow_up, normalize_item, SIMPLE_TEMPLATE, BARE_EVENT_TEMPLATE
|
||||
from .. import blow_up
|
||||
|
||||
|
||||
class EmptyNetrc(object):
|
||||
def __init__(self, file=None):
|
||||
self._file = file
|
||||
|
||||
def authenticators(self, hostname):
|
||||
return None
|
||||
|
||||
|
||||
class EmptyKeyring(object):
|
||||
def get_password(self, *a, **kw):
|
||||
return None
|
||||
|
|
@ -40,49 +42,6 @@ def empty_password_storages(monkeypatch):
|
|||
monkeypatch.setattr(utils, 'keyring', EmptyKeyring())
|
||||
|
||||
|
||||
def test_parse_options():
|
||||
o = {
|
||||
'foo': 'yes',
|
||||
'hah': 'true',
|
||||
'bar': '',
|
||||
'baz': 'whatever',
|
||||
'bam': '123',
|
||||
'asd': 'off'
|
||||
}
|
||||
|
||||
a = dict(utils.parse_options(o.items()))
|
||||
|
||||
expected = {
|
||||
'foo': True,
|
||||
'hah': True,
|
||||
'bar': '',
|
||||
'baz': 'whatever',
|
||||
'bam': 123,
|
||||
'asd': False
|
||||
}
|
||||
|
||||
assert a == expected
|
||||
|
||||
for key in a:
|
||||
# Yes, we want a very strong typecheck here, because we actually have
|
||||
# to differentiate between bool and int, and in Python 2, bool is a
|
||||
# subclass of int.
|
||||
assert type(a[key]) is type(expected[key]) # flake8: noqa
|
||||
|
||||
|
||||
def test_parse_config_value():
|
||||
with pytest.raises(ValueError):
|
||||
utils.parse_config_value('123 # comment!')
|
||||
|
||||
assert utils.parse_config_value('"123 # comment!"') == '123 # comment!'
|
||||
assert utils.parse_config_value('True') is True
|
||||
assert utils.parse_config_value('False') is False
|
||||
assert utils.parse_config_value('Yes') is True
|
||||
assert utils.parse_config_value('3.14') == 3.14
|
||||
assert utils.parse_config_value('') == ''
|
||||
assert utils.parse_config_value('""') == ''
|
||||
|
||||
|
||||
def test_get_password_from_netrc(monkeypatch):
|
||||
username = 'foouser'
|
||||
password = 'foopass'
|
||||
|
|
@ -133,9 +92,9 @@ def test_get_password_from_command(tmpdir):
|
|||
filepath = str(tmpdir) + '/' + filename
|
||||
f = open(filepath, 'w')
|
||||
f.write('#!/bin/sh\n'
|
||||
'[ "$1" != "my_username" ] && exit 1\n'
|
||||
'[ "$2" != "example.com" ] && exit 1\n'
|
||||
'echo "{}"'.format(password))
|
||||
'[ "$1" != "my_username" ] && exit 1\n'
|
||||
'[ "$2" != "example.com" ] && exit 1\n'
|
||||
'echo "{}"'.format(password))
|
||||
f.close()
|
||||
|
||||
st = os.stat(filepath)
|
||||
|
|
@ -144,7 +103,7 @@ def test_get_password_from_command(tmpdir):
|
|||
@doubleclick.click.command()
|
||||
@doubleclick.click.pass_context
|
||||
def fake_app(ctx):
|
||||
ctx.obj = {'config' : ({'password_command' : filepath},{},{})}
|
||||
ctx.obj = {'config': ({'password_command': filepath}, {}, {})}
|
||||
_password = utils.get_password(username, resource)
|
||||
assert _password == password
|
||||
|
||||
|
|
@ -154,8 +113,6 @@ def test_get_password_from_command(tmpdir):
|
|||
|
||||
|
||||
def test_get_password_from_prompt():
|
||||
getpass_calls = []
|
||||
|
||||
user = 'my_user'
|
||||
resource = 'http://example.com'
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ from .. import DOCS_HOME, PROJECT_HOME, log
|
|||
from ..doubleclick import click
|
||||
from ..storage import storage_names
|
||||
from ..sync import StorageEmpty, SyncConflict
|
||||
from ..utils import expand_path, get_class_init_args, parse_options, \
|
||||
safe_write
|
||||
from ..utils import expand_path, get_class_init_args, safe_write
|
||||
from ..utils.compat import text_type
|
||||
|
||||
|
||||
|
|
@ -465,3 +464,56 @@ class WorkerQueue(object):
|
|||
|
||||
def put(self, f):
|
||||
return self._queue.put(f)
|
||||
|
||||
|
||||
def parse_config_value(value):
|
||||
try:
|
||||
return json.loads(value)
|
||||
except ValueError:
|
||||
rv = value
|
||||
|
||||
if value.lower() in ('on', 'true', 'yes'):
|
||||
cli_logger.warning(
|
||||
'{} is deprecated for the config, please use true.\n'
|
||||
'The old form will be removed in 0.4.0.'
|
||||
.format(value)
|
||||
)
|
||||
return True
|
||||
if value.lower() in ('off', 'false', 'no'):
|
||||
cli_logger.warning(
|
||||
'{} is deprecated for the config, please use false.\n'
|
||||
'The old form will be removed in 0.4.0.'
|
||||
.format(value)
|
||||
)
|
||||
return False
|
||||
if value.lower() == 'none':
|
||||
cli_logger.warning(
|
||||
'None is deprecated for the config, please use null.\n'
|
||||
'The old form will be removed in 0.4.0.'
|
||||
)
|
||||
return None
|
||||
|
||||
if '#' in value:
|
||||
raise ValueError('Invalid value:{}\n'
|
||||
'Use double quotes (") if you want to use hashes in '
|
||||
'your value.')
|
||||
|
||||
if len(value.splitlines()) > 1:
|
||||
# ConfigParser's barrier for mistaking an arbitrary line for the
|
||||
# continuation of a value is awfully low. The following example will
|
||||
# also contain the second line in the value:
|
||||
#
|
||||
# foo = bar
|
||||
# # my comment
|
||||
raise ValueError('No multiline-values allowed:\n{!r}'.format(value))
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def parse_options(items, section=None):
|
||||
for key, value in items:
|
||||
try:
|
||||
yield key, parse_config_value(value)
|
||||
except ValueError as e:
|
||||
raise ValueError('Section {!r}, option {!r}: {}'
|
||||
.format(section, key, e))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
:license: MIT, see LICENSE for more details.
|
||||
'''
|
||||
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
|
||||
|
|
@ -68,53 +67,6 @@ def uniq(s):
|
|||
yield x
|
||||
|
||||
|
||||
def parse_config_value(value):
|
||||
try:
|
||||
return json.loads(value)
|
||||
except ValueError:
|
||||
rv = value
|
||||
|
||||
if value.lower() in ('on', 'true', 'yes'):
|
||||
logger.warning('{} is deprecated for the config, please use true.\n'
|
||||
'The old form will be removed in 0.4.0.'
|
||||
.format(value))
|
||||
return True
|
||||
if value.lower() in ('off', 'false', 'no'):
|
||||
logger.warning('{} is deprecated for the config, please use false.\n'
|
||||
'The old form will be removed in 0.4.0.'
|
||||
.format(value))
|
||||
return False
|
||||
if value.lower() == 'none':
|
||||
logger.warning('None is deprecated for the config, please use null.\n'
|
||||
'The old form will be removed in 0.4.0.')
|
||||
return None
|
||||
|
||||
if '#' in value:
|
||||
raise ValueError('Invalid value:{}\n'
|
||||
'Use double quotes (") if you want to use hashes in '
|
||||
'your value.')
|
||||
|
||||
if len(value.splitlines()) > 1:
|
||||
# ConfigParser's barrier for mistaking an arbitrary line for the
|
||||
# continuation of a value is awfully low. The following example will
|
||||
# also contain the second line in the value:
|
||||
#
|
||||
# foo = bar
|
||||
# # my comment
|
||||
raise ValueError('No multiline-values allowed:\n{!r}'.format(value))
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
def parse_options(items, section=None):
|
||||
for key, value in items:
|
||||
try:
|
||||
yield key, parse_config_value(value)
|
||||
except ValueError as e:
|
||||
raise ValueError('Section {!r}, option {!r}: {}'
|
||||
.format(section, key, e))
|
||||
|
||||
|
||||
def get_password(username, resource, _lock=threading.Lock()):
|
||||
"""tries to access saved password or asks user for it
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue