mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-05 10:45:51 +00:00
Improve docstrings and comments
This commit is contained in:
parent
666ffe6afc
commit
d263a399f3
2 changed files with 102 additions and 49 deletions
|
|
@ -157,6 +157,20 @@ def storage_instance_from_config(config, description=None):
|
|||
|
||||
|
||||
def expand_collection(pair, collection, all_pairs, all_storages):
|
||||
'''
|
||||
Replace the placeholder collections "from a" and "from b" with actual
|
||||
ones.
|
||||
|
||||
:param collection: The collection.
|
||||
:param pair: The pair the collection belongs to.
|
||||
:param all_pairs: dictionary: pair_name => (name of storage a,
|
||||
name of storage b,
|
||||
pair config,
|
||||
storage defaults)
|
||||
:returns: One or more collections that replace the given one. The original
|
||||
collection is returned unmodified if the given collection is neither
|
||||
"from a" nor "from b".
|
||||
'''
|
||||
if collection in ('from a', 'from b'):
|
||||
a_name, b_name, _, storage_defaults = all_pairs[pair]
|
||||
config = dict(storage_defaults)
|
||||
|
|
@ -171,6 +185,10 @@ def expand_collection(pair, collection, all_pairs, all_storages):
|
|||
|
||||
|
||||
def parse_pairs_args(pairs_args, all_pairs):
|
||||
'''
|
||||
Expand the various CLI shortforms ("pair, pair/collection") to an iterable
|
||||
of (pair, collection).
|
||||
'''
|
||||
if not pairs_args:
|
||||
pairs_args = list(all_pairs)
|
||||
for pair_and_collection in pairs_args:
|
||||
|
|
@ -196,6 +214,8 @@ def parse_pairs_args(pairs_args, all_pairs):
|
|||
for c in collections:
|
||||
yield pair, c
|
||||
|
||||
# We create the app inside a factory and destroy that factory after first use
|
||||
# to avoid pollution of the module namespace.
|
||||
|
||||
def _create_app():
|
||||
def catch_errors(f):
|
||||
|
|
|
|||
|
|
@ -69,10 +69,8 @@ def parse_options(items, section=None):
|
|||
# # my comment
|
||||
#
|
||||
# For reasons beyond my understanding ConfigParser only requires
|
||||
# one space to interpret the line as part of a multiline-value.
|
||||
# Related to that, it also parses any inline-comments as value:
|
||||
#
|
||||
# foo = bar # this comment is part of the value!
|
||||
# one space to interpret the line as part of a multiline-value,
|
||||
# therefore "bar\n # my comment" will be the value of foo.
|
||||
raise ValueError('Section {!r}, option {!r}: '
|
||||
'No multiline-values allowed.'
|
||||
.format(section, key))
|
||||
|
|
@ -89,6 +87,47 @@ def parse_options(items, section=None):
|
|||
yield key, value
|
||||
|
||||
|
||||
def get_password(username, resource):
|
||||
"""tries to access saved password or asks user for it
|
||||
|
||||
will try the following in this order:
|
||||
1. read password from netrc (and only the password, username
|
||||
in netrc will be ignored)
|
||||
2. read password from keyring (keyring needs to be installed)
|
||||
3a ask user for the password
|
||||
b save in keyring if installed and user agrees
|
||||
|
||||
:param username: user's name on the server
|
||||
:type username: str/unicode
|
||||
:param resource: a resource to which the user has access via password,
|
||||
it will be shortened to just the hostname. It is assumed
|
||||
that each unique username/hostname combination only ever
|
||||
uses the same password.
|
||||
:type resource: str/unicode
|
||||
:return: password
|
||||
:rtype: str/unicode
|
||||
|
||||
|
||||
"""
|
||||
for func in (_password_from_netrc, _password_from_keyring):
|
||||
password = func(username, resource)
|
||||
if password is not None:
|
||||
logger.debug('Got password for {} from {}'
|
||||
.format(username, func.__doc__))
|
||||
return password
|
||||
|
||||
prompt = ('Server password for {} at the resource {}'
|
||||
.format(username, resource))
|
||||
password = click.prompt(prompt, hide_input=True)
|
||||
|
||||
if keyring is not None and \
|
||||
click.confirm('Save this password in the keyring?', default=False):
|
||||
keyring.set_password(password_key_prefix + resource,
|
||||
username, password)
|
||||
|
||||
return password
|
||||
|
||||
|
||||
def _password_from_netrc(username, resource):
|
||||
'''.netrc'''
|
||||
from netrc import netrc
|
||||
|
|
@ -137,50 +176,20 @@ def _password_from_keyring(username, resource):
|
|||
key = new_key
|
||||
|
||||
|
||||
def get_password(username, resource):
|
||||
"""tries to access saved password or asks user for it
|
||||
|
||||
will try the following in this order:
|
||||
1. read password from netrc (and only the password, username
|
||||
in netrc will be ignored)
|
||||
2. read password from keyring (keyring needs to be installed)
|
||||
3a ask user for the password
|
||||
b save in keyring if installed and user agrees
|
||||
|
||||
:param username: user's name on the server
|
||||
:type username: str/unicode
|
||||
:param resource: a resource to which the user has access via password,
|
||||
it will be shortened to just the hostname. It is assumed
|
||||
that each unique username/hostname combination only ever
|
||||
uses the same password.
|
||||
:type resource: str/unicode
|
||||
:return: password
|
||||
:rtype: str/unicode
|
||||
|
||||
|
||||
"""
|
||||
for func in (_password_from_netrc, _password_from_keyring):
|
||||
password = func(username, resource)
|
||||
if password is not None:
|
||||
logger.debug('Got password for {} from {}'
|
||||
.format(username, func.__doc__))
|
||||
return password
|
||||
|
||||
prompt = ('Server password for {} at the resource {}'
|
||||
.format(username, resource))
|
||||
password = click.prompt(prompt, hide_input=True)
|
||||
|
||||
if keyring is not None and \
|
||||
click.confirm('Save this password in the keyring?', default=False):
|
||||
keyring.set_password(password_key_prefix + resource,
|
||||
username, password)
|
||||
|
||||
return password
|
||||
|
||||
|
||||
def request(method, url, data=None, headers=None, auth=None, verify=None,
|
||||
session=None, latin1_fallback=True):
|
||||
'''wrapper method for requests, to ease logging and mocking'''
|
||||
'''
|
||||
Wrapper method for requests, to ease logging and mocking. Parameters should
|
||||
be the same as for ``requests.request``, except:
|
||||
|
||||
:param session: A requests session object to use.
|
||||
:param latin1_fallback: RFC-2616 specifies the default Content-Type of
|
||||
text/* to be latin1, which is not always correct, but exactly what
|
||||
requests is doing. Setting this parameter to False will use charset
|
||||
autodetection (usually ending up with utf8) instead of plainly falling
|
||||
back to this silly default. See
|
||||
https://github.com/kennethreitz/requests/issues/2042
|
||||
'''
|
||||
|
||||
if session is None:
|
||||
func = requests.request
|
||||
|
|
@ -215,13 +224,23 @@ def request(method, url, data=None, headers=None, auth=None, verify=None,
|
|||
|
||||
|
||||
class safe_write(object):
|
||||
'''A helper class for performing atomic writes. Writes to a tempfile in
|
||||
the same directory and then renames. The tempfile location can be
|
||||
overridden, but must reside on the same filesystem to be atomic.
|
||||
|
||||
Usage::
|
||||
|
||||
with safe_write(fpath, 'w+') as f:
|
||||
f.write('hohoho')
|
||||
'''
|
||||
|
||||
f = None
|
||||
tmppath = None
|
||||
fpath = None
|
||||
mode = None
|
||||
|
||||
def __init__(self, fpath, mode):
|
||||
self.tmppath = fpath + '.tmp'
|
||||
def __init__(self, fpath, mode, tmppath=None):
|
||||
self.tmppath = tmppath or fpath + '.tmp'
|
||||
self.fpath = fpath
|
||||
self.mode = mode
|
||||
|
||||
|
|
@ -271,7 +290,15 @@ def get_class_init_args(cls):
|
|||
return all | s_all, required | s_required
|
||||
|
||||
|
||||
def checkdir(path, create=False):
|
||||
def checkdir(path, create=False, mode=0o750):
|
||||
'''
|
||||
Check whether ``path`` is a directory.
|
||||
|
||||
:param create: Whether to create the directory (and all parent directories)
|
||||
if it does not exist.
|
||||
:param mode: Mode to create missing directories with.
|
||||
'''
|
||||
|
||||
if not os.path.isdir(path):
|
||||
if os.path.exists(path):
|
||||
raise IOError('{} is not a directory.'.format(path))
|
||||
|
|
@ -285,6 +312,12 @@ def checkdir(path, create=False):
|
|||
|
||||
|
||||
def checkfile(path, create=False):
|
||||
'''
|
||||
Check whether ``path`` is a file.
|
||||
|
||||
:param create: Whether to create the file's parent directories if they do
|
||||
not exist.
|
||||
'''
|
||||
checkdir(os.path.dirname(path), create=create)
|
||||
if not os.path.isfile(path):
|
||||
if os.path.exists(path):
|
||||
|
|
|
|||
Loading…
Reference in a new issue