Add example configuration to storage docs

This commit is contained in:
Markus Unterwaditzer 2014-12-27 16:43:49 +01:00
parent 8c93247aa0
commit 8933da7db4
8 changed files with 75 additions and 36 deletions

View file

@ -89,6 +89,31 @@ def github_issue_role(name, rawtext, text, lineno, inliner, options={},
return [node], []
from sphinx.ext import autodoc
class StorageDocumenter(autodoc.ClassDocumenter):
'''Custom formatter for auto-documenting storage classes. It assumes that
the first line of the class' docstring is its own paragraph.
After that first paragraph, an example configuration will be inserted and
Sphinx' __init__ signature removed.'''
objtype = 'storage'
directivetype = 'attribute'
def format_signature(self):
return ''
def get_doc(self, encoding=None, ignore=1):
from vdirsyncer.cli.utils import format_storage_config
rv = autodoc.ClassDocumenter.get_doc(self, encoding, ignore)
config = [u' ' + x for x in format_storage_config(self.object)]
rv[0] = rv[0][:1] + [u'::', u''] + config + [u''] + rv[0][1:]
return rv
def setup(app):
app.add_role('gh', github_issue_role)
app.add_role('ghpr', github_issue_role)
app.add_autodocumenter(StorageDocumenter)

View file

@ -126,13 +126,13 @@ These storages generally support reading and changing of their items. Their
default value for ``read_only`` is ``false``, but can be set to ``true`` if
wished.
.. autoclass:: CaldavStorage
.. autostorage:: CaldavStorage
.. autoclass:: CarddavStorage
.. autostorage:: CarddavStorage
.. autoclass:: FilesystemStorage
.. autostorage:: FilesystemStorage
.. autoclass:: SingleFileStorage
.. autostorage:: SingleFileStorage
Read-only storages
~~~~~~~~~~~~~~~~~~
@ -141,4 +141,4 @@ These storages don't support writing of their items, consequently ``read_only``
is set to ``true`` by default. Changing ``read_only`` to ``false`` on them
leads to an error.
.. autoclass:: HttpStorage
.. autostorage:: HttpStorage

View file

@ -517,3 +517,17 @@ def parse_options(items, section=None):
except ValueError as e:
raise ValueError('Section {!r}, option {!r}: {}'
.format(section, key, e))
def format_storage_config(cls, header=True):
if header is True:
yield '[storage {}]'.format(cls.storage_name)
from ..storage.base import Storage
from ..utils import get_class_init_specs
for spec in get_class_init_specs(cls, stop_at=Storage):
defaults = dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
for key in spec.args[1:]:
comment = '' if key not in defaults else '#'
value = defaults.get(key, '...')
yield '{}{} = {}'.format(comment, key, json.dumps(value))

View file

@ -253,12 +253,6 @@ class DavSession(object):
class DavStorage(Storage):
'''
.. note::
Please also see :doc:`supported` for very important information, as
changing some of the default options might be very dangerous with some
servers.
:param url: Base URL or an URL to a collection.
:param username: Username for authentication.
:param password: Password for authentication.
@ -272,6 +266,12 @@ class DavStorage(Storage):
:param useragent: Default ``vdirsyncer``.
:param unsafe_href_chars: Replace the given characters when generating
hrefs. Defaults to ``'@'``.
.. note::
Please also see :doc:`supported` for very important information, as
changing some of the default options might be very dangerous with some
servers.
'''
# the file extension of items. Useful for testing against radicale.
@ -478,7 +478,7 @@ class DavStorage(Storage):
class CaldavStorage(DavStorage):
__doc__ = '''
CalDAV. Usable as ``caldav`` in the config file.
CalDAV.
You can set a timerange to synchronize with the parameters ``start_date``
and ``end_date``. Inside those parameters, you can use any Python
@ -492,15 +492,13 @@ class CaldavStorage(DavStorage):
Either both or none have to be specified. The default is to synchronize
everything.
''' + DavStorage.__doc__ + '''
:param start_date: Start date of timerange to show, default -inf.
:param end_date: End date of timerange to show, default +inf.
:param item_types: Comma-separated collection types to show from the
server. Dependent on server functionality, no clientside validation of
results. The empty value ``''`` is the same as ``'VTODO, VEVENT,
VJOURNAL'``.
'''
''' + DavStorage.__doc__
storage_name = 'caldav'
fileext = '.ics'
@ -625,7 +623,7 @@ class CaldavStorage(DavStorage):
class CarddavStorage(DavStorage):
__doc__ = '''
CardDAV. Usable as ``carddav`` in the config file.
CardDAV.
''' + DavStorage.__doc__
storage_name = 'carddav'

View file

@ -20,9 +20,10 @@ logger = log.get(__name__)
class FilesystemStorage(Storage):
'''
Saves each item in its own file, given a directory. Can be used with `khal
<http://lostpackets.de/khal/>`_. See :doc:`vdir` for a more formal
description of the format. Usable as ``filesystem`` in the config file.
Saves each item in its own file, given a directory.
Can be used with `khal <http://lostpackets.de/khal/>`_. See :doc:`vdir` for
a more formal description of the format.
:param path: Absolute path to a vdir or collection, depending on the
collection parameter (see :py:class:`vdirsyncer.storage.base.Storage`).

View file

@ -46,8 +46,7 @@ def prepare_verify(verify):
class HttpStorage(Storage):
'''
Use a simple ``.ics`` file (or similar) from the web. Usable as ``http`` in
the config file.
Use a simple ``.ics`` file (or similar) from the web.
:param url: URL to the ``.ics`` file.
:param username: Username for authentication.

View file

@ -20,8 +20,7 @@ logger = log.get(__name__)
class SingleFileStorage(Storage):
'''Save data in single ``.vcf`` or ``.ics`` file. Usable as ``singlefile``
in the config file.
'''Save data in single local ``.vcf`` or ``.ics`` file.
The storage basically guesses how items should be joined in the file.

View file

@ -282,7 +282,17 @@ def get_etag_from_file(fpath):
return '{:.9f}'.format(os.path.getmtime(fpath))
def get_class_init_args(cls):
def get_class_init_specs(cls, stop_at=object):
if cls is stop_at:
return ()
import inspect
spec = inspect.getargspec(cls.__init__)
supercls = next(getattr(x.__init__, '__objclass__', x)
for x in cls.__mro__[1:])
return (spec,) + get_class_init_specs(supercls, stop_at=stop_at)
def get_class_init_args(cls, stop_at=object):
'''
Get args which are taken during class initialization. Assumes that all
classes' __init__ calls super().__init__ with the rest of the arguments.
@ -292,19 +302,12 @@ def get_class_init_args(cls):
class can take, and ``required`` is the subset of arguments the class
requires.
'''
import inspect
all, required = set(), set()
for spec in get_class_init_specs(cls, stop_at=stop_at):
all.update(spec.args[1:])
required.update(spec.args[1:-len(spec.defaults or ())])
if cls is object:
return set(), set()
spec = inspect.getargspec(cls.__init__)
all = set(spec.args[1:])
required = set(spec.args[1:-len(spec.defaults or ())])
supercls = next(getattr(x.__init__, '__objclass__', x)
for x in cls.__mro__[1:])
s_all, s_required = get_class_init_args(supercls)
return all | s_all, required | s_required
return all, required
def checkdir(path, create=False, mode=0o750):