diff --git a/bonobo/commands/run.py b/bonobo/commands/run.py index 0a11577..cc82022 100644 --- a/bonobo/commands/run.py +++ b/bonobo/commands/run.py @@ -3,10 +3,7 @@ import os import bonobo from bonobo.constants import DEFAULT_SERVICES_ATTR, DEFAULT_SERVICES_FILENAME -DEFAULT_GRAPH_FILENAMES = ( - '__main__.py', - 'main.py', -) +DEFAULT_GRAPH_FILENAMES = ('__main__.py', 'main.py',) DEFAULT_GRAPH_ATTR = 'get_graph' diff --git a/bonobo/config/configurables.py b/bonobo/config/configurables.py index 85ecdde..47c87e2 100644 --- a/bonobo/config/configurables.py +++ b/bonobo/config/configurables.py @@ -1,5 +1,5 @@ -from bonobo.util import isoption, iscontextprocessor, sortedlist from bonobo.errors import AbstractError +from bonobo.util import isoption, iscontextprocessor, sortedlist, get_name __all__ = [ 'Configurable', @@ -37,6 +37,26 @@ class ConfigurableMeta(type): cls.__names.add(name) cls.__options.insort((not value.positional, value._creation_counter, name, value)) + # Docstring formating + _options_doc = [] + for _positional, _counter, _name, _value in cls.__options: + _param = _name + if _value.type: + _param = get_name(_value.type) + ' ' + _param + + prefix = ':param {}: '.format(_param) + for lineno, line in enumerate((_value.__doc__ or '').split('\n')): + _options_doc.append((' ' * len(prefix) if lineno else prefix) + line) + cls.__doc__ = '\n\n'.join( + map( + str.strip, + filter(None, ( + cls.__doc__, + '\n'.join(_options_doc) + )) + ) + ) + @property def __options__(cls): return ((name, option) for _, _, name, option in cls.__options) diff --git a/bonobo/config/options.py b/bonobo/config/options.py index 2fd9491..2b92f47 100644 --- a/bonobo/config/options.py +++ b/bonobo/config/options.py @@ -1,3 +1,5 @@ +from textwrap import dedent + from bonobo.util.inspect import istype @@ -60,7 +62,12 @@ class Option: self.positional = positional self.default = default - self.__doc__ = __doc__ or self.__doc__ + # Docstring formating + self.__doc__ = __doc__ or None + if self.__doc__: + self.__doc__ = dedent(self.__doc__.strip('\n')).strip() + if default: + self.__doc__ += '\nDefault: {!r}'.format(default) # This hack is necessary for python3.5 self._creation_counter = Option._creation_counter diff --git a/bonobo/nodes/io/base.py b/bonobo/nodes/io/base.py index 496a0e8..c59195a 100644 --- a/bonobo/nodes/io/base.py +++ b/bonobo/nodes/io/base.py @@ -5,14 +5,16 @@ from bonobo.structs.bags import Bag class IOFormatEnabled(Configurable): - ioformat = Option(default=settings.IOFORMAT.get) + ioformat = Option(default=settings.IOFORMAT.get, __doc__=''' + Input/output format for rows. This will be removed in 0.6, so please use the kwargs format. + ''') def get_input(self, *args, **kwargs): if self.ioformat == settings.IOFORMAT_ARG0: if len(args) != 1 or len(kwargs): raise UnrecoverableValueError( 'Wrong input formating: IOFORMAT=ARG0 implies one arg and no kwargs, got args={!r} and kwargs={!r}.'. - format(args, kwargs) + format(args, kwargs) ) return args[0] @@ -20,7 +22,7 @@ class IOFormatEnabled(Configurable): if len(args) or not len(kwargs): raise UnrecoverableValueError( 'Wrong input formating: IOFORMAT=KWARGS ioformat implies no arg, got args={!r} and kwargs={!r}.'. - format(args, kwargs) + format(args, kwargs) ) return kwargs @@ -40,17 +42,26 @@ class FileHandler(Configurable): """Abstract component factory for file-related components. Args: - path (str): which path to use within the provided filesystem. - eol (str): which character to use to separate lines. + eol (str): which mode (str): which mode to use when opening the file. fs (str): service name to use for filesystem. """ - path = Option(str, required=True, positional=True) # type: str - eol = Option(str, default='\n') # type: str - mode = Option(str) # type: str - encoding = Option(str, default='utf-8') # type: str - fs = Service('fs') # type: str + path = Option(str, required=True, positional=True, __doc__=''' + Path to use within the provided filesystem. + ''') # type: str + eol = Option(str, default='\n', __doc__=''' + Character to use as line separator. + ''') # type: str + mode = Option(str, __doc__=''' + What mode to use for open() call. + ''') # type: str + encoding = Option(str, default='utf-8', __doc__=''' + Encoding. + ''') # type: str + fs = Service('fs', __doc__=''' + The filesystem instance to use. + ''') # type: str @ContextProcessor def file(self, context, fs): diff --git a/bonobo/nodes/io/csv.py b/bonobo/nodes/io/csv.py index 31222fb..e141af5 100644 --- a/bonobo/nodes/io/csv.py +++ b/bonobo/nodes/io/csv.py @@ -3,43 +3,33 @@ import csv from bonobo.config import Option from bonobo.config.processors import ContextProcessor from bonobo.constants import NOT_MODIFIED -from bonobo.nodes.io.file import FileReader, FileWriter from bonobo.nodes.io.base import FileHandler, IOFormatEnabled +from bonobo.nodes.io.file import FileReader, FileWriter from bonobo.util.objects import ValueHolder class CsvHandler(FileHandler): - """ - - .. attribute:: delimiter - - The CSV delimiter. - - .. attribute:: quotechar - - The CSV quote character. - - .. attribute:: headers - - The list of column names, if the CSV does not contain it as its first line. - - """ - delimiter = Option(str, default=';') - quotechar = Option(str, default='"') - headers = Option(tuple, required=False) + delimiter = Option(str, default=';', __doc__=''' + Delimiter used between values. + ''') + quotechar = Option(str, default='"', __doc__=''' + Character used for quoting values. + ''') + headers = Option(tuple, required=False, __doc__=''' + Tuple of headers to use, if provided. + Readers will try to guess that from first line, unless this option is provided. + Writers will guess from kwargs keys, unless this option is provided. + ''') class CsvReader(IOFormatEnabled, FileReader, CsvHandler): """ Reads a CSV and yield the values as dicts. - - .. attribute:: skip - - The amount of lines to skip before it actually yield output. - """ - skip = Option(int, default=0) + skip = Option(int, default=0, __doc__=''' + If set and greater than zero, the reader will skip this amount of lines. + ''') @ContextProcessor def csv_headers(self, context, fs, file): diff --git a/bonobo/nodes/io/file.py b/bonobo/nodes/io/file.py index e49d6de..34a585f 100644 --- a/bonobo/nodes/io/file.py +++ b/bonobo/nodes/io/file.py @@ -12,7 +12,9 @@ class FileReader(Reader, FileHandler): present. Extending it is usually the right way to create more specific file readers (like json, csv, etc.) """ - mode = Option(str, default='r') + mode = Option(str, default='r', __doc__=''' + What mode to use for open() call. + ''') # type: str def read(self, fs, file): """ @@ -30,7 +32,9 @@ class FileWriter(Writer, FileHandler): usually the right way to create more specific file writers (like json, csv, etc.) """ - mode = Option(str, default='w+') + mode = Option(str, default='w+', __doc__=''' + What mode to use for open() call. + ''') # type: str @ContextProcessor def lineno(self, context, fs, file): diff --git a/bonobo/structs/tokens.py b/bonobo/structs/tokens.py index 325a3b8..9ef6f64 100644 --- a/bonobo/structs/tokens.py +++ b/bonobo/structs/tokens.py @@ -1,8 +1,9 @@ class Token: - """Factory for signal oriented queue messages or other token types.""" + """Token factory.""" def __init__(self, name): self.__name__ = name + self.__doc__ = 'The {!r} token.'.format(name) def __repr__(self): return '<{}>'.format(self.__name__) diff --git a/docs/reference/api.rst b/docs/reference/api.rst index e401b9c..3d6f7c7 100644 --- a/docs/reference/api.rst +++ b/docs/reference/api.rst @@ -4,9 +4,6 @@ Bonobo API The Bonobo API, available directly under the :mod:`bonobo` package, contains all the tools you need to get started with bonobo. -The :mod:`bonobo` package -::::::::::::::::::::::::: - .. automodule:: bonobo :members: :undoc-members: