Commits

Georg Brandl committed 5463dcc

Add new universal config value ``exclude_patterns``, with glob-style exclude patterns.

This makes the old ``unused_docs``, ``exclude_trees`` and ``exclude_dirnames`` obsolete.

  • Participants
  • Parent commits 22893e5

Comments (0)

Files changed (10)

 Release 1.0 (in development)
 ============================
 
+* The new universal config value ``exclude_patterns`` makes the
+  old ``unused_docs``, ``exclude_trees`` and ``exclude_dirnames``
+  obsolete.
+
 * Remove the deprecated ``exclude_dirs`` config value.
 
 * #129: Wrap toctrees in a div tag with class ``toctree-wrapper``
 # The master toctree document.
 master_doc = 'contents'
 
+exclude_patterns = ['_build']
+
 # General substitutions.
 project = 'Sphinx'
 copyright = '2007-2010, Georg Brandl'

File doc/config.rst

    The document name of the "master" document, that is, the document that
    contains the root :dir:`toctree` directive.  Default is ``'contents'``.
 
+.. confval:: exclude_patterns
+
+   A list of glob-style patterns that should be excluded when looking for source
+   files. [#]_ They are matched against the source file names relative to the
+   source directory, using slashes as directory separators on all platforms.
+
+   Example patterns:
+
+   - ``'library/xml.rst'`` -- ignores the ``library/xml.rst`` file (replaces
+     entry in :confval:`unused_docs`
+   - ``'library/xml'`` -- ignores the ``library/xml`` directory (replaces entry
+     in :confval:`exclude_trees`)
+   - ``'library/xml*'`` -- ignores all files and directories starting with
+     ``library/xml``
+   - ``'**/.svn'`` -- ignores all ``.svn`` directories (replaces entry in
+     :confval:`exclude_dirnames`)
+
+   :confval:`exclude_patterns` is also consulted when looking for static files
+   in :confval:`html_static_path`.
+
+   .. versionadded:: 1.0
+
 .. confval:: unused_docs
 
    A list of document names that are present, but not currently included in the
    toctree.  Use this setting to suppress the warning that is normally emitted
    in that case.
 
+   .. deprecated:: 1.0
+      Use :confval:`exclude_patterns` instead.
+
 .. confval:: exclude_trees
 
    A list of directory paths, relative to the source directory, that are to be
 
    .. versionadded:: 0.4
 
+   .. deprecated:: 1.0
+      Use :confval:`exclude_patterns` instead.
+
 .. confval:: exclude_dirnames
 
    A list of directory names that are to be excluded from any recursive
 
    .. versionadded:: 0.5
 
+   .. deprecated:: 1.0
+      Use :confval:`exclude_patterns` instead.
+
 .. confval:: locale_dirs
 
    .. versionadded:: 0.5
 
    .. deprecated:: 0.5
       Use the ``'pointsize'`` key in the :confval:`latex_elements` value.
+
+
+.. rubric:: Footnotes
+
+.. [#] A note on available globbing syntax: you can use the standard shell
+       constructs ``*``, ``?``, ``[...]`` and ``[!...]`` with the feature that
+       these all don't match slashes.  A double star ``**`` can be used to match
+       any sequence of characters *including* slashes.

File sphinx/config.py

         master_doc = ('contents', 'env'),
         source_suffix = ('.rst', 'env'),
         source_encoding = ('utf-8-sig', 'env'),
+        exclude_patterns = ([], 'env'),
+        # the next three are all deprecated now
         unused_docs = ([], 'env'),
         exclude_trees = ([], 'env'),
         exclude_dirnames = ([], 'env'),

File sphinx/environment.py

         """
         Find all source files in the source dir and put them in self.found_docs.
         """
-        exclude_trees = [d.replace(SEP, path.sep) for d in config.exclude_trees]
+        patterns = config.exclude_patterns[:]
+        patterns += config.exclude_trees
+        patterns += [d + config.source_suffix for d in config.unused_docs]
+        patterns += ['**/' + d for d in config.exclude_dirnames]
+        patterns += ['**/_sources']
         self.found_docs = set(get_matching_docs(
-            self.srcdir, config.source_suffix,
-            exclude_docs=set(config.unused_docs),
-            exclude_trees=exclude_trees,
-            exclude_dirnames=['_sources'] + config.exclude_dirnames))
+            self.srcdir, config.source_suffix, exclude_patterns=patterns))
 
     def get_outdated_files(self, config_changed):
         """

File sphinx/quickstart.py

 # Else, today_fmt is used as the format for a strftime call.
 #today_fmt = '%%B %%d, %%Y'
 
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# List of directories, relative to source directory, that shouldn't be searched
-# for source files.
-exclude_trees = [%(exclude_trees)s]
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = [%(exclude_patterns)s]
 
 # The reST default role (used for this markup: `text`) to use for all documents.
 #default_role = None
     mkdir_p(srcdir)
     if d['sep']:
         builddir = path.join(d['path'], 'build')
-        d['exclude_trees'] = ''
+        d['exclude_patterns'] = ''
     else:
         builddir = path.join(srcdir, d['dot'] + 'build')
-        d['exclude_trees'] = repr(d['dot'] + 'build')
+        d['exclude_patterns'] = repr(d['dot'] + 'build')
     mkdir_p(builddir)
     mkdir_p(path.join(srcdir, d['dot'] + 'templates'))
     mkdir_p(path.join(srcdir, d['dot'] + 'static'))

File sphinx/util/__init__.py

         yield top, dirs, nondirs
 
 
-def get_matching_docs(dirname, suffix, exclude_docs=(), exclude_dirs=(),
-                      exclude_trees=(), exclude_dirnames=()):
+def get_matching_files(dirname, exclude_patterns=()):
+    """
+    Get all file names in a directory, recursively.
+
+    Exclude files and dirs matching a pattern in *exclude_patterns*.
+    """
+    # dirname is a normalized absolute path.
+    dirname = path.normpath(path.abspath(dirname))
+    dirlen = len(dirname) + 1    # exclude final os.path.sep
+
+    matchers = [re.compile(_translate_pattern(pat)).match
+                for pat in exclude_patterns]
+
+    for root, dirs, files in walk(dirname, followlinks=True):
+        relativeroot = root[dirlen:]
+
+        qdirs = enumerate(path.join(relativeroot, dir).replace(os.path.sep, SEP)
+                          for dir in dirs)
+        qfiles = enumerate(path.join(relativeroot, file).replace(os.path.sep, SEP)
+                           for file in files)
+        for matcher in matchers:
+            qdirs = [entry for entry in qdirs if not matcher(entry[1])]
+            qfiles = [entry for entry in qfiles if not matcher(entry[1])]
+
+        dirs[:] = sorted(dirs[i] for (i, _) in qdirs)
+
+        for i, filename in sorted(qfiles):
+            yield filename
+
+
+def get_matching_docs(dirname, suffix, exclude_patterns=()):
     """
     Get all file names (without suffix) matching a suffix in a
     directory, recursively.
 
-    Exclude docs in *exclude_docs*, exclude dirs in *exclude_dirs*,
-    prune dirs in *exclude_trees*, prune dirnames in *exclude_dirnames*.
+    Exclude files and dirs matching a pattern in *exclude_patterns*.
     """
-    pattern = '*' + suffix
-    # dirname is a normalized absolute path.
-    dirname = path.normpath(path.abspath(dirname))
-    dirlen = len(dirname) + 1    # exclude slash
-    for root, dirs, files in walk(dirname, followlinks=True):
-        if root[dirlen:] in exclude_dirs:
+    suffixpattern = '*' + suffix
+    for filename in get_matching_files(dirname, exclude_patterns):
+        if not fnmatch.fnmatch(filename, suffixpattern):
             continue
-        if root[dirlen:] in exclude_trees:
-            del dirs[:]
-            continue
-        dirs.sort()
-        files.sort()
-        for prunedir in exclude_dirnames:
-            if prunedir in dirs:
-                dirs.remove(prunedir)
-        for sfile in files:
-            if not fnmatch.fnmatch(sfile, pattern):
-                continue
-            qualified_name = path.join(root[dirlen:], sfile[:-len(suffix)])
-            qualified_name = qualified_name.replace(os.path.sep, SEP)
-            if qualified_name in exclude_docs:
-                continue
-            yield qualified_name
+        yield filename[:-len(suffix)]
 
 
 def mtimes_of_files(dirnames, suffix):

File tests/root/conf.py

 release = '0.6alpha1'
 today_fmt = '%B %d, %Y'
 #unused_docs = []
-exclude_trees = ['_build']
+exclude_patterns = ['_build', '**/excluded.*']
 keep_warnings = True
 pygments_style = 'sphinx'
 

File tests/root/subdir/excluded.txt

+Excluded file -- should *not* be read as source
+-----------------------------------------------

File tests/test_env.py

     for docname in it:  # the generator does all the work
         docnames.add(docname)
     assert docnames == env.found_docs == set(env.all_docs)
+    # test if exclude_patterns works ok
+    assert 'subdir/excluded' not in env.found_docs
 
 def test_images():
     assert warning_emitted('images.txt', 'image file not readable: foo.png')