4
Process docstrings with Sphinx
6
Processes docstrings with Sphinx. Can also be used as a commandline script:
8
``python sphinxify.py <text>``
12
- Tim Joseph Dumol (2009-09-29): initial version
13
- Carlos Cordoba (2010-09-21): Some changes to make it work with Spyder
15
Taken from the Sage project
16
http://www.sagemath.org/
18
#**************************************************
19
# Copyright (C) 2009 Tim Dumol <tim@timdumol.com>
21
# Distributed under the terms of the BSD License
22
#**************************************************
28
from tempfile import mkdtemp
31
from sphinx.application import Sphinx #@UnusedImport
32
from docutils.utils import SystemMessage as SystemMessage
35
from spyderlib.baseconfig import get_module_source_path
36
from spyderlib.utils import encoding
38
# Note: we do not use __file__ because it won't be working in the stand-alone
39
# version of Spyder (i.e. the py2exe or cx_Freeze build)
40
CSS_PATH = osp.join(get_module_source_path('spyderlib.utils'), 'css')
43
def is_sphinx_markup(docstring):
45
Returns whether a string that contains Sphinx-style ReST markup.
49
- ``docstring`` - string to test for markup
55
# this could be made much more clever
56
return ("`" in docstring or "::" in docstring)
59
def sphinxify(docstring, format='html'):
61
Runs Sphinx on a ``docstring``, and outputs the processed
66
- ``docstring`` -- string -- a ReST-formatted docstring
68
- ``format`` -- string (optional, default 'html') -- either 'html' or
73
- string -- Sphinx-processed documentation, in either HTML or
74
plain text format, depending on the value of ``format``
78
>>> from spyderlib.plugins.sphinxify import sphinxify
79
>>> sphinxify('A test')
80
'\n<div class="docstring">\n \n <p>A test</p>\n\n\n</div>'
81
>>> sphinxify('**Testing**\n`monospace`')
82
'\n<div class="docstring">\n \n <p><strong>Testing</strong>\n<span class="math">monospace</span></p>\n\n\n</div>'
83
>>> sphinxify('`x=y`')
84
'\n<div class="docstring">\n \n <p><span class="math">x=y</span></p>\n\n\n</div>'
85
>>> sphinxify('`x=y`', format='text')
87
>>> sphinxify(':math:`x=y`', format='text')
92
from sphinx.application import Sphinx
95
srcdir = encoding.to_unicode_from_fs(srcdir)
97
base_name = os.path.join(srcdir, 'docstring')
98
rst_name = base_name + '.rst'
104
output_name = base_name + suffix
106
# This is needed for jsMath to work.
107
docstring = docstring.replace('\\\\', '\\')
109
filed = codecs.open(rst_name, 'w', encoding='utf-8')
110
filed.write(docstring)
113
# Sphinx constructor: Sphinx(srcdir, confdir, outdir, doctreedir,
114
# buildername, confoverrides, status, warning, freshenv).
116
# This may be inefficient. TODO: Find a faster way to do this.
119
confdir = encoding.to_unicode_from_fs(confdir)
120
generate_configuration(confdir)
122
doctreedir = os.path.join(srcdir, 'doctrees')
123
confoverrides = {'html_context': {}, 'master_doc': 'docstring'}
125
sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, format,
126
confoverrides, None, None, True)
128
sphinx_app.build(None, [rst_name])
129
except SystemMessage:
130
output = '<div id=\"warning\"> \
131
It\'s not possible to generate rich text help for this object. \
132
Please see it in plain text. \
136
if os.path.exists(output_name):
137
output = codecs.open(output_name, 'r', encoding='utf-8').read()
138
output = output.replace('<pre>', '<pre class="literal-block">')
140
# Translate URLs for media from something like
141
# "../../media/...path.../blah.png"
143
# "/media/...path.../blah.png"
145
# "/doc/static/reference/media/...path.../blah.png"
146
output = re.sub("""src=['"](/?\.\.)*/?media/([^"']*)['"]""",
147
'src="/doc/static/reference/media/\\2"',
150
print "BUG -- Sphinx error"
152
output = '<pre class="introspection">%s</pre>' % docstring
157
shutil.rmtree(confdir, ignore_errors=True)
158
shutil.rmtree(srcdir, ignore_errors=True)
163
def generate_configuration(directory):
165
Generates a Sphinx configuration in ``directory``.
169
- ``directory`` - string, base directory to use
173
>>> from spyderlib.plugins.sphinxify import generate_configuration
174
>>> import tempfile, os
175
>>> tmpdir = tempfile.mkdtemp()
176
>>> generate_configuration(tmpdir)
177
>>> open(os.path.join(tmpdir, 'conf.py')).read()
178
'\n...extensions =...templates_path...source = False\n...'
181
###########################################################
182
# Taken from `$SAGE_ROOT$/devel/sage/doc/common/conf.py` #
183
###########################################################
185
# If your extensions are in another directory, add it here. If the directory
186
# is relative to the documentation root, use os.path.abspath to make it
187
# absolute, like shown here.
188
#sys.path.append(os.path.abspath('.'))
190
# General configuration
191
# ---------------------
193
# Add any Sphinx extension module names here, as strings. They can be extensions
194
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
195
extensions = ['sphinx.ext.autodoc']
197
jsmath_path = 'easy/load.js'
199
# The suffix of source filenames.
200
source_suffix = '.rst'
202
# The master toctree document.
205
# General information about the project.
207
copyright = u'2009--2011, The Spyder Development Team'
210
# The full version, including alpha/beta/rc tags.
213
# The language for content autogenerated by Sphinx. Refer to documentation
214
# for a list of supported languages.
217
# There are two options for replacing |today|: either, you set today to some
218
# non-false value, then it is used:
220
# Else, today_fmt is used as the format for a strftime call.
221
#today_fmt = '%B %d, %Y'
223
# List of documents that shouldn't be included in the build.
226
# List of directories, relative to source directory, that shouldn't be searched
228
exclude_trees = ['.build']
230
# The reST default role (used for this markup: `text`) to use for all documents.
231
default_role = 'math'
233
# If true, '()' will be appended to :func: etc. cross-reference text.
234
#add_function_parentheses = True
236
# If true, the current module name will be prepended to all description
237
# unit titles (such as .. function::).
238
#add_module_names = True
240
# If true, sectionauthor and moduleauthor directives will be shown in the
241
# output. They are ignored by default.
242
#show_authors = False
244
# The name of the Pygments (syntax highlighting) style to use.
245
pygments_style = 'sphinx'
248
# Options for HTML output
249
# -----------------------
251
# The style sheet to use for HTML and HTML Help pages. A file of that name
252
# must exist either in Sphinx' static/ path, or in one of the custom paths
253
# given in html_static_path.
254
html_style = 'default.css'
256
# The name for this set of Sphinx documents. If None, it defaults to
257
# "<project> v<release> documentation".
260
# A shorter title for the navigation bar. Default is the same as html_title.
261
#html_short_title = None
263
# The name of an image file (within the static path) to place at the top of
267
# The name of an image file (within the static path) to use as favicon of the
268
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
270
#html_favicon = 'favicon.ico'
272
# If we're using jsMath, we prepend its location to the static path
273
# array. We can override / overwrite selected files by putting them
274
# in the remaining paths.
275
#if 'SAGE_DOC_JSMATH' in os.environ:
276
# jsmath_static = os.path.join(SAGE_ROOT, 'local/notebook/javascript/jsmath')
277
# html_static_path.insert(0, jsmath_static)
279
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
280
# using the given strftime format.
281
#html_last_updated_fmt = '%b %d, %Y'
283
# If true, SmartyPants will be used to convert quotes and dashes to
284
# typographically correct entities.
285
#html_use_smartypants = True
287
# Custom sidebar templates, maps document names to template names.
290
# Additional templates that should be rendered to pages, maps page names to
292
#html_additional_pages = {}
294
# If false, no module index is generated.
295
#html_use_modindex = True
297
# If false, no index is generated.
298
#html_use_index = True
300
# If true, the reST sources are included in the HTML build as _sources/<name>.
301
#html_copy_source = True
303
# If true, an OpenSearch description file will be output, and all pages will
304
# contain a <link> tag referring to it. The value of this option must be the
305
# base URL from which the finished HTML is served.
306
#html_use_opensearch = ''
308
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
309
#html_file_suffix = ''
311
# Output file base name for HTML help builder.
312
#htmlhelp_basename = ''
315
# Options for LaTeX output
316
# ------------------------
318
# The paper size ('letter' or 'a4').
319
#latex_paper_size = 'letter'
321
# The font size ('10pt', '11pt' or '12pt').
322
#latex_font_size = '10pt'
324
# Grouping the document tree into LaTeX files. List of tuples
325
# (source start file, target name, title, author, document class [howto/manual]).
328
# The name of an image file (relative to this directory) to place at the top of
332
# For "manual" documents, if this is true, then toplevel headings are parts,
334
#latex_use_parts = False
336
# Additional stuff for the LaTeX preamble.
338
latex_preamble = '\usepackage{amsmath}\n\usepackage{amsfonts}\n'
340
# Documents to append as an appendix to all manuals.
341
#latex_appendices = []
343
# If false, no module index is generated.
344
#latex_use_modindex = True
346
#####################################################
347
# add LaTeX macros for Sage
349
# from sage.misc.latex_macros import sage_latex_macros
351
sage_latex_macros = []
354
pngmath_latex_preamble # check whether this is already defined
356
pngmath_latex_preamble = ""
358
for macro in sage_latex_macros:
359
# used when building latex and pdf versions
360
latex_preamble += macro + '\n'
361
# used when building html version
362
pngmath_latex_preamble += macro + '\n'
364
#####################################################
365
def process_docstring_aliases(app, what, name, obj, options, docstringlines):
367
Change the docstrings for aliases to point to the original object.
369
basename = name.rpartition('.')[2]
370
if hasattr(obj, '__name__') and obj.__name__ != basename:
371
docstringlines[:] = ['See :obj:`%s`.' % name]
373
def process_directives(app, what, name, obj, options, docstringlines):
375
Remove 'nodetex' and other directives from the first line of any
376
docstring where they appear.
378
if len(docstringlines) == 0:
380
first_line = docstringlines[0]
381
directives = [ d.lower() for d in first_line.split(',') ]
382
if 'nodetex' in directives:
383
docstringlines.pop(0)
385
def process_docstring_cython(app, what, name, obj, options, docstringlines):
387
Remove Cython's filename and location embedding.
389
if len(docstringlines) <= 1:
392
first_line = docstringlines[0]
393
if first_line.startswith('File:') and '(starting at' in first_line:
394
#Remove the first two lines
395
docstringlines.pop(0)
396
docstringlines.pop(0)
398
def process_docstring_module_title(app, what, name, obj, options, docstringlines):
400
Removes the first line from the beginning of the module's docstring. This
401
corresponds to the title of the module's documentation page.
406
#Remove any additional blank lines at the beginning
407
title_removed = False
408
while len(docstringlines) > 1 and not title_removed:
409
if docstringlines[0].strip() != "":
411
docstringlines.pop(0)
413
#Remove any additional blank lines at the beginning
414
while len(docstringlines) > 1:
415
if docstringlines[0].strip() == "":
416
docstringlines.pop(0)
421
app.connect('autodoc-process-docstring', process_docstring_cython)
422
app.connect('autodoc-process-docstring', process_directives)
423
app.connect('autodoc-process-docstring', process_docstring_module_title)
425
#################################################################
426
# Taken from `$SAGE_ROOT$/devel/sage/doc/en/introspect/conf.py` #
427
#################################################################
429
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath']
431
templates_path = ['templates']
432
html_static_path = ['static']
434
html_use_modindex = False
435
html_use_index = False
436
html_split_index = False
437
html_copy_source = False
440
# From SAGE_DOC/en/introspect/templates/layout.html:
442
<div class="docstring">
443
{% block body %}{% endblock %}
446
os.makedirs(os.path.join(directory, 'templates'))
447
os.makedirs(os.path.join(directory, 'static'))
448
open(os.path.join(directory, 'conf.py'), 'w').write(conf)
449
open(os.path.join(directory, '__init__.py'), 'w').write('')
450
open(os.path.join(directory, 'templates', 'layout.html'),
452
open(os.path.join(directory, 'static', 'empty'), 'w').write('')
454
if __name__ == '__main__':
456
if len(sys.argv) == 2:
457
print sphinxify(sys.argv[1])
462
docstring -- docstring to be processed