diff --git a/docs/Makefile b/docs/Makefile index 8358bed..049f749 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -76,7 +76,7 @@ source/interactive/magics-generated.txt: autogen_magics.py autoconfig: source/config/options/config-generated.txt -source/config/options/config-generated.txt: +source/config/options/config-generated.txt: autogen_config.py $(PYTHON) autogen_config.py @echo "Created docs for config options" diff --git a/docs/autogen_config.py b/docs/autogen_config.py index 1579d5f..c6996a8 100755 --- a/docs/autogen_config.py +++ b/docs/autogen_config.py @@ -4,11 +4,65 @@ from os.path import join, dirname, abspath from IPython.terminal.ipapp import TerminalIPythonApp from ipykernel.kernelapp import IPKernelApp +from traitlets import Undefined here = abspath(dirname(__file__)) options = join(here, 'source', 'config', 'options') generated = join(options, 'config-generated.txt') +from ipython_genutils.text import indent, dedent + +def interesting_default_value(dv): + if (dv is None) or (dv is Undefined): + return False + if isinstance(dv, (str, list, tuple, dict, set)): + return bool(dv) + return True + +def class_config_rst_doc(cls): + """Generate rST documentation for this class' config options. + + Excludes traits defined on parent classes. + """ + lines = [] + classname = cls.__name__ + for k, trait in sorted(cls.class_traits(config=True).items()): + ttype = trait.__class__.__name__ + + lines += ['.. configtrait:: ' + classname + '.' + trait.name, + '' + ] + + help = trait.help.rstrip() or 'No description' + lines.append(indent(dedent(help), 4) + '\n') + + # Choices or type + if 'Enum' in ttype: + # include Enum choices + lines.append(indent( + ':options: ' + ', '.join('``%r``' % x for x in trait.values), 4)) + else: + lines.append(indent(':trait type: ' + ttype, 4)) + + # Default value + # Ignore boring default values like None, [] or '' + if interesting_default_value(trait.default_value): + try: + dvr = trait.default_value_repr() + except Exception: + dvr = None # ignore defaults we can't construct + if dvr is not None: + if len(dvr) > 64: + dvr = dvr[:61] + '...' + # Double up backslashes, so they get to the rendered docs + dvr = dvr.replace('\\n', '\\\\n') + lines.append(indent(':default: ``%s``' % dvr, 4)) + + # Blank line + lines.append('') + + return '\n'.join(lines) + def write_doc(name, title, app, preamble=None): filename = join(options, name+'.rst') @@ -18,7 +72,11 @@ def write_doc(name, title, app, preamble=None): f.write('\n') if preamble is not None: f.write(preamble + '\n\n') - f.write(app.document_config_options()) + #f.write(app.document_config_options()) + + for c in app._classes_inc_parents(): + f.write(class_config_rst_doc(c)) + f.write('\n') if __name__ == '__main__': diff --git a/docs/source/conf.py b/docs/source/conf.py index a260eed..e060572 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -62,6 +62,7 @@ extensions = [ 'sphinx.ext.napoleon', # to preprocess docstrings 'github', # for easy GitHub links 'magics', + 'configtraits', ] if ON_RTD: diff --git a/docs/sphinxext/configtraits.py b/docs/sphinxext/configtraits.py new file mode 100644 index 0000000..4e76769 --- /dev/null +++ b/docs/sphinxext/configtraits.py @@ -0,0 +1,17 @@ +"""Directives and roles for documenting traitlets config options. + +:: + + .. configtrait:: Application.log_datefmt + + Description goes here. + + Cross reference like this: :configtrait:`Application.log_datefmt`. +""" +from sphinx.locale import l_ +from sphinx.util.docfields import Field + +def setup(app): + app.add_object_type('configtrait', 'configtrait', objname='Config option') + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata