Commits

georg.brandl  committed de96e31

Merged revisions 64808,65013,65076,65100-65101,65119,65121-65123 via svnmerge from
svn+ssh://pythondev@svn.python.org/doctools/branches/0.4.x

........
r64808 | georg.brandl | 2008-07-08 21:39:33 +0200 (Tue, 08 Jul 2008) | 2 lines

Allow relocation of source and doctree dir.
........
r65013 | georg.brandl | 2008-07-16 15:25:30 +0200 (Wed, 16 Jul 2008) | 2 lines

Remove curious quote.
........
r65076 | georg.brandl | 2008-07-17 22:43:01 +0200 (Thu, 17 Jul 2008) | 2 lines

Add a test for sphinx.quickstart.
........
r65100 | georg.brandl | 2008-07-18 14:41:54 +0200 (Fri, 18 Jul 2008) | 2 lines

Fix phony targets.
........
r65101 | georg.brandl | 2008-07-18 14:55:03 +0200 (Fri, 18 Jul 2008) | 2 lines

Fix problems in "make check".
........
r65119 | georg.brandl | 2008-07-18 23:06:42 +0200 (Fri, 18 Jul 2008) | 2 lines

Emit a more precise error message in autodoc.
........
r65121 | georg.brandl | 2008-07-18 23:41:35 +0200 (Fri, 18 Jul 2008) | 2 lines

Warn if a toctree-included document doesn't contain a title.
........
r65122 | georg.brandl | 2008-07-18 23:51:28 +0200 (Fri, 18 Jul 2008) | 2 lines

Don't use \samp{} for code with whitespaces, only for :samp:`code`.
........
r65123 | georg.brandl | 2008-07-19 00:49:46 +0200 (Sat, 19 Jul 2008) | 2 lines

Put inheritance info always on its own line.
........

  • Participants
  • Parent commits 65d68ef

Comments (0)

Files changed (17)

 
 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
 
 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 <ul>s in tocs
 - autoattribute in autodoc
 - range and object options for literalinclude

File sphinx/__init__.py

         print >>sys.stderr
     print >>sys.stderr, """\
 Sphinx v%s
-Usage: %s [options] sourcedir outdir [filenames...]"
+Usage: %s [options] sourcedir outdir [filenames...]
 Options: -b <builder> -- 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

File sphinx/builder.py

         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):

File sphinx/environment.py

 
         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
                     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),
             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

File sphinx/ext/autodoc.py

             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)
                      u':class:`%s.%s`' % (b.__module__, b.__name__)
                      for b in todoc.__bases__]
             result.append(indent + u'   Bases: %s' % ', '.join(bases), '<autodoc>')
+            result.append(u'', '<autodoc>')
 
     # the module directive doesn't have content
     if what != 'module':

File sphinx/latexwriter.py

         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)

File sphinx/quickstart.py

 from sphinx.util.console import purple, bold, red, nocolor
 
 
+PROMPT_PREFIX = '> '
+
 QUICKSTART_CONF = '''\
 # -*- coding: utf-8 -*-
 #
 # 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
 # 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
 
 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
 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"
     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'])

File sphinx/roles.py

 
 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 = {

File sphinx/templates/genindex-split.html

    <h1 id="index">Index</h1>
 
    <p>Index pages by letter:</p>
-     
+
    <p>{% for key, dummy in genindexentries -%}
    <a href="{{ pathto('genindex-' + key) }}"><strong>{{ key }}</strong></a>
      {% if not loop.last %}| {% endif %}
    {%- endfor %}</p>
 
    <p><a href="{{ pathto('genindex-all') }}"><strong>Full index on one page</strong></a></p>
-{% endif %} 
+{% endif %}
 {% endblock %}

File sphinx/templates/genindex.html

    {%- endfor %}</p>
 
    <p><a href="{{ pathto('genindex-all') }}"><strong>Full index on one page</strong></a></p>
-{% endif %} 
+{% endif %}
 {% endblock %}

File sphinx/util/__init__.py

     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)

File sphinx/util/console.py

 def nocolor():
     codes.clear()
 
+def coloron():
+    codes.update(_orig_codes)
+
 def colorize(name, text):
     return codes.get(name, '') + text + codes.get('reset', '')
 
     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)

File tests/path.py

         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'):

File tests/test_quickstart.py

+# -*- 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()

File tests/util.py

 __all__ = [
     'raises', 'raises_msg',
     'ErrorOutput', 'TestApp',
-    'with_tempdir', 'write_file',
+    'path', 'with_tempdir', 'write_file',
 ]
 
 

File utils/check_sources.py

     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.
 """
 
     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: