diff --git a/Makefile b/Makefile
index 6ed9cad16..8c39230eb 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ PYTHON ?= python
export PYTHONPATH = $(shell echo "$$PYTHONPATH"):./sphinx
-.PHONY: all check clean clean-pyc pylint reindent testserver
+.PHONY: all check clean clean-pyc clean-patchfiles pylint reindent test
all: clean-pyc check
diff --git a/TODO b/TODO
index 619c21230..293dcc9b2 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,10 @@
Sphinx TODO
===========
+- specify node visit functions when adding nodes to app
+- allow extensions to add static files
+- decide which static files to include
+- verbose option
- remove redundant
s in tocs
- autoattribute in autodoc
- range and object options for literalinclude
diff --git a/sphinx/__init__.py b/sphinx/__init__.py
index 4f67ca4d5..b40838fac 100644
--- a/sphinx/__init__.py
+++ b/sphinx/__init__.py
@@ -29,7 +29,7 @@ def usage(argv, msg=None):
print >>sys.stderr
print >>sys.stderr, """\
Sphinx v%s
-Usage: %s [options] sourcedir outdir [filenames...]"
+Usage: %s [options] sourcedir outdir [filenames...]
Options: -b -- builder to use; default is html
-a -- write all files; default is to only write new and changed files
-E -- don't use a saved environment, always read all files
diff --git a/sphinx/builder.py b/sphinx/builder.py
index 988f1df30..5f137ee60 100644
--- a/sphinx/builder.py
+++ b/sphinx/builder.py
@@ -211,7 +211,7 @@ class Builder(object):
warnings = []
self.env.set_warnfunc(warnings.append)
self.info(bold('updating environment: '), nonl=1)
- iterator = self.env.update(self.config, self.app)
+ iterator = self.env.update(self.config, self.srcdir, self.doctreedir, self.app)
# the first item in the iterator is a summary message
self.info(iterator.next())
for docname in self.status_iterator(iterator, 'reading... ', purple):
diff --git a/sphinx/environment.py b/sphinx/environment.py
index f0696cedc..039d3c385 100644
--- a/sphinx/environment.py
+++ b/sphinx/environment.py
@@ -396,7 +396,7 @@ class BuildEnvironment:
return added, changed, removed
- def update(self, config, app=None):
+ def update(self, config, srcdir, doctreedir, app=None):
"""(Re-)read all files new or changed since last update. Yields a summary
and then docnames as it processes them. Store all environment docnames
in the canonical format (ie using SEP as a separator in place of
@@ -416,6 +416,9 @@ class BuildEnvironment:
break
else:
msg = ''
+ # the source and doctree directories may have been relocated
+ self.srcdir = srcdir
+ self.doctreedir = doctreedir
self.find_files(config)
added, changed, removed = self.get_outdated_files(config_changed)
msg += '%s added, %s changed, %s removed' % (len(added), len(changed),
@@ -807,10 +810,15 @@ class BuildEnvironment:
for includefile in includefiles:
try:
toc = self.tocs[includefile].deepcopy()
+ if not toc.children:
+ # empty toc means: no titles will show up in the toctree
+ self.warn(docname, 'toctree contains reference to document '
+ '%r that doesn\'t have a title: no link will be '
+ 'generated' % includefile)
except KeyError:
# this is raised if the included file does not exist
- self.warn(docname, 'toctree contains ref to nonexisting '
- 'file %r' % includefile)
+ self.warn(docname, 'toctree contains reference to nonexisting '
+ 'document %r' % includefile)
else:
# if titles_only is given, only keep the main title and
# sub-toctrees
diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py
index 45dcb7b9e..74f59c13f 100644
--- a/sphinx/ext/autodoc.py
+++ b/sphinx/ext/autodoc.py
@@ -355,10 +355,11 @@ def generate_rst(what, name, members, options, add_content, document, lineno,
modfile = None # e.g. for builtin and C modules
for part in objpath:
todoc = getattr(todoc, part)
- except (ImportError, AttributeError):
+ except (ImportError, AttributeError), err:
warnings.append(document.reporter.warning(
- 'autodoc can\'t import/find %s %r, check your spelling '
- 'and sys.path' % (what, str(fullname)), line=lineno))
+ 'autodoc can\'t import/find %s %r, it reported error: "%s",'
+ 'please check your spelling and sys.path' %
+ (what, str(fullname), err), line=lineno))
return warnings, result
# check __module__ of object if wanted (for members not given explicitly)
@@ -416,6 +417,7 @@ def generate_rst(what, name, members, options, add_content, document, lineno,
u':class:`%s.%s`' % (b.__module__, b.__name__)
for b in todoc.__bases__]
result.append(indent + u' Bases: %s' % ', '.join(bases), '')
+ result.append(u'', '')
# the module directive doesn't have content
if what != 'module':
diff --git a/sphinx/latexwriter.py b/sphinx/latexwriter.py
index 70905aab0..036fdf7ca 100644
--- a/sphinx/latexwriter.py
+++ b/sphinx/latexwriter.py
@@ -873,7 +873,7 @@ class LaTeXTranslator(nodes.NodeVisitor):
content = self.encode(node.astext().strip())
if self.in_title:
self.body.append(r'\texttt{%s}' % content)
- elif re.search('[ \t\n]', content):
+ elif node.has_key('role') and node['role'] == 'samp':
self.body.append(r'\samp{%s}' % content)
else:
self.body.append(r'\code{%s}' % content)
diff --git a/sphinx/quickstart.py b/sphinx/quickstart.py
index f452e2127..d5781a689 100644
--- a/sphinx/quickstart.py
+++ b/sphinx/quickstart.py
@@ -16,6 +16,8 @@ from sphinx.util import make_filename
from sphinx.util.console import purple, bold, red, nocolor
+PROMPT_PREFIX = '> '
+
QUICKSTART_CONF = '''\
# -*- coding: utf-8 -*-
#
@@ -176,7 +178,8 @@ htmlhelp_basename = '%(project_fn)sdoc'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
- ('%(master)s', '%(project_fn)s.tex', '%(project)s Documentation', '%(author)s', 'manual'),
+ ('%(master)s', '%(project_fn)s.tex', '%(project)s Documentation',
+ '%(author)s', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -231,7 +234,8 @@ PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d %(rbuilddir)s/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) %(rsrcdir)s
+ALLSPHINXOPTS = -d %(rbuilddir)s/doctrees $(PAPEROPT_$(PAPER)) \
+$(SPHINXOPTS) %(rsrcdir)s
.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
@@ -333,9 +337,9 @@ def ok(x):
def do_prompt(d, key, text, default=None, validator=nonempty):
while True:
if default:
- prompt = purple('> %s [%s]: ' % (text, default))
+ prompt = purple(PROMPT_PREFIX + '%s [%s]: ' % (text, default))
else:
- prompt = purple('> ' + text + ': ')
+ prompt = purple(PROMPT_PREFIX + text + ': ')
x = raw_input(prompt)
if default and not x:
x = default
@@ -364,7 +368,7 @@ Enter the root path for documentation.'''
You have two options for placing the build directory for Sphinx output.
Either, you use a directory ".build" within the root path, or you separate
"source" and "build" directories within the root path.'''
- do_prompt(d, 'sep', 'Separate source and build directories (y/n)', 'n',
+ do_prompt(d, 'sep', 'Separate source and build directories (y/N)', 'n',
boolean)
print '''
Inside the root directory, two more directories will be created; ".templates"
@@ -399,14 +403,14 @@ document is a custom template, you can also set this to another filename.'''
print '''
Please indicate if you want to use one of the following Sphinx extensions:'''
do_prompt(d, 'ext_autodoc', 'autodoc: automatically insert docstrings '
- 'from modules (y/n)', 'n', boolean)
+ 'from modules (y/N)', 'n', boolean)
do_prompt(d, 'ext_doctest', 'doctest: automatically test code snippets '
- 'in doctest blocks (y/n)', 'n', boolean)
+ 'in doctest blocks (y/N)', 'n', boolean)
print '''
If you are under Unix, a Makefile can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.'''
- do_prompt(d, 'makefile', 'Create Makefile? (y/n)',
+ do_prompt(d, 'makefile', 'Create Makefile? (Y/n)',
os.name == 'posix' and 'y' or 'n', boolean)
d['project_fn'] = make_filename(d['project'])
diff --git a/sphinx/roles.py b/sphinx/roles.py
index 618b741c3..2cfca3d8b 100644
--- a/sphinx/roles.py
+++ b/sphinx/roles.py
@@ -195,17 +195,17 @@ _litvar_re = re.compile('{([^}]+)}')
def emph_literal_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
text = utils.unescape(text)
- retnodes = []
pos = 0
+ retnode = nodes.literal(role=typ)
for m in _litvar_re.finditer(text):
if m.start() > pos:
txt = text[pos:m.start()]
- retnodes.append(nodes.literal(txt, txt))
- retnodes.append(nodes.emphasis('', '', nodes.literal(m.group(1), m.group(1))))
+ retnode += nodes.Text(txt, txt)
+ retnode += nodes.emphasis(m.group(1), m.group(1))
pos = m.end()
if pos < len(text):
- retnodes.append(nodes.literal(text[pos:], text[pos:]))
- return retnodes, []
+ retnode += nodes.Text(text[pos:], text[pos:])
+ return [retnode], []
specific_docroles = {
diff --git a/sphinx/templates/genindex-split.html b/sphinx/templates/genindex-split.html
index 957fd4c31..be6da9e28 100644
--- a/sphinx/templates/genindex-split.html
+++ b/sphinx/templates/genindex-split.html
@@ -5,7 +5,7 @@
Index
Index pages by letter:
-
+
{% for key, dummy in genindexentries -%}
{{ key }}
{% if not loop.last %}| {% endif %}
@@ -25,5 +25,5 @@
{%- endfor %}
Full index on one page
-{% endif %}
+{% endif %}
{% endblock %}
diff --git a/sphinx/templates/genindex.html b/sphinx/templates/genindex.html
index a11a65a09..ec55b70e8 100644
--- a/sphinx/templates/genindex.html
+++ b/sphinx/templates/genindex.html
@@ -52,5 +52,5 @@
{%- endfor %}
Full index on one page
-{% endif %}
+{% endif %}
{% endblock %}
diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py
index 4dc6502c2..e1621a764 100644
--- a/sphinx/util/__init__.py
+++ b/sphinx/util/__init__.py
@@ -250,7 +250,7 @@ def patfilter(names, pat):
Adapted from fnmatch module.
"""
result = []
- if not pat in _pat_cache:
+ if pat not in _pat_cache:
_pat_cache[pat] = re.compile(_translate_pattern(pat))
match = _pat_cache[pat].match
return filter(match, names)
diff --git a/sphinx/util/console.py b/sphinx/util/console.py
index ea41e2496..05ab7e501 100644
--- a/sphinx/util/console.py
+++ b/sphinx/util/console.py
@@ -38,6 +38,9 @@ def print_and_backspace(text, func):
def nocolor():
codes.clear()
+def coloron():
+ codes.update(_orig_codes)
+
def colorize(name, text):
return codes.get(name, '') + text + codes.get('reset', '')
@@ -73,5 +76,7 @@ for i, (dark, light) in enumerate(_colors):
codes[dark] = '\x1b[%im' % (i+30)
codes[light] = '\x1b[%i;01m' % (i+30)
+_orig_codes = codes.copy()
+
for _name in codes:
create_color_func(_name)
diff --git a/tests/path.py b/tests/path.py
index b4829662d..5ce1d1181 100644
--- a/tests/path.py
+++ b/tests/path.py
@@ -353,7 +353,7 @@ class path(_base):
whose names match the given pattern. For example,
d.files('*.pyc').
"""
-
+
return [p for p in self.listdir(pattern) if p.isfile()]
def walk(self, pattern=None, errors='strict'):
diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py
new file mode 100644
index 000000000..51c9feb1b
--- /dev/null
+++ b/tests/test_quickstart.py
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+"""
+ test_quickstart
+ ~~~~~~~~~~~~~~~
+
+ Test the sphinx.quickstart module.
+
+ :copyright: 2008 by Georg Brandl.
+ :license: BSD.
+"""
+
+import sys
+import time
+import __builtin__
+
+from util import *
+
+from sphinx import quickstart as qs
+from sphinx.util.console import nocolor, coloron
+
+def setup_module():
+ nocolor()
+
+def mock_raw_input(answers, needanswer=False):
+ called = set()
+ def raw_input(prompt):
+ if prompt in called:
+ raise AssertionError('answer for %r missing and no default '
+ 'present' % prompt)
+ called.add(prompt)
+ for question in answers:
+ if prompt.startswith(qs.PROMPT_PREFIX + question):
+ return answers[question]
+ if needanswer:
+ raise AssertionError('answer for %r missing' % prompt)
+ return ''
+ return raw_input
+
+def teardown_module():
+ qs.raw_input = __builtin__.raw_input
+ coloron()
+
+
+def test_do_prompt():
+ d = {}
+ answers = {
+ 'Q2': 'v2',
+ 'Q3': 'v3',
+ 'Q4': 'yes',
+ 'Q5': 'no',
+ 'Q6': 'foo',
+ }
+ qs.raw_input = mock_raw_input(answers)
+ try:
+ qs.do_prompt(d, 'k1', 'Q1')
+ except AssertionError:
+ assert 'k1' not in d
+ else:
+ assert False, 'AssertionError not raised'
+ qs.do_prompt(d, 'k1', 'Q1', default='v1')
+ assert d['k1'] == 'v1'
+ qs.do_prompt(d, 'k3', 'Q3', default='v3_default')
+ assert d['k3'] == 'v3'
+ qs.do_prompt(d, 'k2', 'Q2')
+ assert d['k2'] == 'v2'
+ qs.do_prompt(d, 'k4', 'Q4', validator=qs.boolean)
+ assert d['k4'] == 'yes'
+ qs.do_prompt(d, 'k5', 'Q5', validator=qs.boolean)
+ assert d['k5'] == 'no'
+ raises(AssertionError, qs.do_prompt, d, 'k6', 'Q6', validator=qs.boolean)
+
+@with_tempdir
+def test_quickstart_defaults(tempdir):
+ answers = {
+ 'Root path': tempdir,
+ 'Project name': 'Sphinx Test',
+ 'Author name': 'Georg Brandl',
+ 'Project version': '0.1',
+ }
+ qs.raw_input = mock_raw_input(answers)
+ qs.inner_main([])
+
+ conffile = tempdir / 'conf.py'
+ assert conffile.isfile()
+ ns = {}
+ execfile(conffile, ns)
+ assert ns['extensions'] == []
+ assert ns['templates_path'] == ['.templates']
+ assert ns['source_suffix'] == '.rst'
+ assert ns['master_doc'] == 'index'
+ assert ns['project'] == 'Sphinx Test'
+ assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y')
+ assert ns['version'] == '0.1'
+ assert ns['release'] == '0.1'
+ assert ns['html_static_path'] == ['.static']
+ assert ns['latex_documents'] == [
+ ('index', 'SphinxTest.tex', 'Sphinx Test Documentation',
+ 'Georg Brandl', 'manual')]
+
+ assert (tempdir / '.static').isdir()
+ assert (tempdir / '.templates').isdir()
+ assert (tempdir / 'index.rst').isfile()
+ assert (tempdir / 'Makefile').isfile()
+
+@with_tempdir
+def test_quickstart_all_answers(tempdir):
+ answers = {
+ 'Root path': tempdir,
+ 'Separate source and build': 'y',
+ 'Name prefix for templates': '_',
+ 'Project name': 'Sphinx Test',
+ 'Author name': 'Georg Brandl',
+ 'Project version': '0.1',
+ 'Project release': '0.1.1',
+ 'Source file suffix': '.txt',
+ 'Name of your master document': 'contents',
+ 'autodoc': 'y',
+ 'doctest': 'yes',
+ 'Create Makefile': 'no',
+ }
+ qs.raw_input = mock_raw_input(answers, needanswer=True)
+ qs.inner_main([])
+
+ conffile = tempdir / 'source' / 'conf.py'
+ assert conffile.isfile()
+ ns = {}
+ execfile(conffile, ns)
+ assert ns['extensions'] == ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
+ assert ns['templates_path'] == ['_templates']
+ assert ns['source_suffix'] == '.txt'
+ assert ns['master_doc'] == 'contents'
+ assert ns['project'] == 'Sphinx Test'
+ assert ns['copyright'] == '%s, Georg Brandl' % time.strftime('%Y')
+ assert ns['version'] == '0.1'
+ assert ns['release'] == '0.1.1'
+ assert ns['html_static_path'] == ['_static']
+ assert ns['latex_documents'] == [
+ ('contents', 'SphinxTest.tex', 'Sphinx Test Documentation',
+ 'Georg Brandl', 'manual')]
+
+ assert (tempdir / 'build').isdir()
+ assert (tempdir / 'source' / '_static').isdir()
+ assert (tempdir / 'source' / '_templates').isdir()
+ assert (tempdir / 'source' / 'contents.txt').isfile()
diff --git a/tests/util.py b/tests/util.py
index 033cc934d..754a4ddab 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -19,7 +19,7 @@ from path import path
__all__ = [
'raises', 'raises_msg',
'ErrorOutput', 'TestApp',
- 'with_tempdir', 'write_file',
+ 'path', 'with_tempdir', 'write_file',
]
diff --git a/utils/check_sources.py b/utils/check_sources.py
index 525256076..0f834fcab 100755
--- a/utils/check_sources.py
+++ b/utils/check_sources.py
@@ -7,7 +7,7 @@
Make sure each Python file has a correct file header
including copyright and license information.
- :copyright: 2006-2007 by Georg Brandl.
+ :copyright: 2006-2008 by Georg Brandl.
:license: GNU GPL, see LICENSE for more details.
"""
@@ -57,15 +57,17 @@ def check_style_and_encoding(fn, lines):
for lno, line in enumerate(lines):
if len(line) > 90:
yield lno+1, "line too long"
+ if lno < 2:
+ co = coding_re.search(line)
+ if co:
+ encoding = co.group(1)
+ if line.strip().startswith('#'):
+ continue
m = not_ix_re.search(line)
if m:
yield lno+1, '"' + m.group() + '"'
if is_const_re.search(line):
yield lno+1, 'using == None/True/False'
- if lno < 2:
- co = coding_re.search(line)
- if co:
- encoding = co.group(1)
try:
line.decode(encoding)
except UnicodeDecodeError, err: