SF.net SVN: docutils:[9543] trunk/docutils

milde--- via Docutils-checkins <[email protected]>
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 9543
          http://sourceforge.net/p/docutils/code/9543
Author:   milde
Date:     2024-02-17 10:37:34 +0000 (Sat, 17 Feb 2024)
Log Message:
-----------
New and fixed options for the "buildhtml.py" front end tool.

New option "rst-sources": The default converts all files matching the
patterns "*.txt" or "*.rst".

Evaluate "prune" setting values as glob-style patterns,
this is the behaviour documented in the online help.
Matching uses `fnmatch.fnmatch()`
(no special handling of "/", "\" and ".").

The default prunes auxiliary directories for popular version
control tools and Python.

Modified Paths:
--------------
    trunk/docutils/HISTORY.txt
    trunk/docutils/RELEASE-NOTES.txt
    trunk/docutils/docs/user/tools.txt
    trunk/docutils/docutils.conf
    trunk/docutils/tools/buildhtml.py

Modified: trunk/docutils/HISTORY.txt
===================================================================
--- trunk/docutils/HISTORY.txt	2024-02-17 10:37:23 UTC (rev 9542)
+++ trunk/docutils/HISTORY.txt	2024-02-17 10:37:34 UTC (rev 9543)
@@ -134,8 +134,6 @@
 
 * docutils/writers/html5_polyglot/\*.css
 
-  - Embed SVG images as ``<svg>`` instead of data-URI
-    (not used by "html4css1"). Fixes [feature-request:#100].
   - Move MathML styles to "minimal.css" (required for correct rendering).
 
 * docutils/writers/_html_base.py
@@ -152,6 +150,8 @@
   - Consider the root-prefix_ setting when converting an image URI
     to a local filesystem path.
   - New <image> attribute "loading" overrides "image-loading" setting.
+  - Embed SVG images as ``<svg>`` instead of data-URI
+    (not used by "html4css1").  Fixes [feature-request:#100].
   - Write system messages for errors/warnings during the writing stage
     (image transformations, math content conversion, ...).
 
@@ -185,7 +185,12 @@
     __ docs/user/config.html#theme-url
     __ docs/user/config.html#theme
 
+* tools/buildhtml.py
 
+  - New option `rst_sources`_.
+    Match `prune` values with `fnmatch.fnmatch()`.
+
+
 Release 0.20.1 (2023-05-17)
 ===========================
 
@@ -4374,6 +4379,7 @@
 .. _output_encoding: docs/user/config.html#output-encoding
 .. _raw_enabled: docs/user/config.html#raw-enabled
 .. _reference_label: docs/user/config.html#reference-label
+.. _rst_sources: docs/user/config.html#rst-sources
 .. _smart_quotes: docs/user/config.html#smart-quotes
 .. _strip_classes: docs/user/config.html#strip-classes
 .. _strip_elements_with_classes: docs/user/config.html#strip-elements-with-classes

Modified: trunk/docutils/RELEASE-NOTES.txt
===================================================================
--- trunk/docutils/RELEASE-NOTES.txt	2024-02-17 10:37:23 UTC (rev 9542)
+++ trunk/docutils/RELEASE-NOTES.txt	2024-02-17 10:37:34 UTC (rev 9543)
@@ -196,9 +196,11 @@
 
 * Configuration changes:
 
-  - New configuration setting root-prefix_.
+  - New configuration setting root_prefix_.
     Configurable root directory for included files.
 
+  - New configuration setting rst_sources_ for the "buildhtml.py" application.
+
   - Simpler and more secure `input encoding`_ default behaviour:
 
     Do not use the locale encoding as fallback if Python is started in
@@ -247,7 +249,8 @@
 .. _input encoding: docs/api/publisher.html#encodings
 .. _csv-table: docs/ref/rst/directives.html#csv-table
 .. _"image" directive: docs/ref/rst/directives.html#image
-.. _root-prefix: docs/user/config.html#root-prefix
+.. _root_prefix: docs/user/config.html#root-prefix
+.. _rst_sources: docs/user/config.html#rst-sources
 
 
 Release 0.20.1 (2023-05-17)

Modified: trunk/docutils/docs/user/tools.txt
===================================================================
--- trunk/docutils/docs/user/tools.txt	2024-02-17 10:37:23 UTC (rev 9542)
+++ trunk/docutils/docs/user/tools.txt	2024-02-17 10:37:34 UTC (rev 9543)
@@ -343,9 +343,9 @@
 The ``buildhtml.py`` script can be found in the ``/tools`` directory of
 the "docutils" source. It is not included in binary packages. [#]_
 
-Use ``buildhtml.py`` to generate ``*.html`` from all the ``*.txt`` files
-(including PEPs) in each <directory> given, and their subdirectories
-too.  (Use the ``--local`` option to skip subdirectories.)
+Use ``buildhtml.py`` to generate ``*.html`` from all the reStructuredText
+source files (including PEPs) in each <directory> given, and their
+subdirectories too.  (Use the ``--local`` option to skip subdirectories.)
 
 Usage::
 

Modified: trunk/docutils/docutils.conf
===================================================================
--- trunk/docutils/docutils.conf	2024-02-17 10:37:23 UTC (rev 9542)
+++ trunk/docutils/docutils.conf	2024-02-17 10:37:34 UTC (rev 9543)
@@ -24,4 +24,4 @@
 writer: html5
 # Prevent tools/buildhtml.py from processing certain text files.
 ignore: GPL2.txt:header.txt:header0.txt:header2.txt:cheatsheet.txt
-prune: .svn:.hg:build:dist:docs/.svn:docutils:docutils.egg-info:licenses:test:tools
+prune: build:dist:docutils:docutils.egg-info:licenses:test:tools

Modified: trunk/docutils/tools/buildhtml.py
===================================================================
--- trunk/docutils/tools/buildhtml.py	2024-02-17 10:37:23 UTC (rev 9542)
+++ trunk/docutils/tools/buildhtml.py	2024-02-17 10:37:34 UTC (rev 9543)
@@ -5,12 +5,11 @@
 # Copyright: This module has been placed in the public domain.
 
 """
-Generates .html from all the .txt files in a directory.
+Generate .html from all reStructuredText files in a directory.
 
-Ordinary .txt files are understood to be standalone reStructuredText.
-Files named ``pep-*.txt`` are interpreted as reStructuredText PEPs.
+Source files are understood to be standalone reStructuredText documents.
+Files with names starting ``pep-`` are interpreted as reStructuredText PEPs.
 """
-# Once PySource is here, build .html from .py as well.
 
 __docformat__ = 'reStructuredText'
 
@@ -29,7 +28,7 @@
 
 import docutils
 import docutils.io
-from docutils import core, frontend, utils, ApplicationError
+from docutils import core, frontend, ApplicationError
 from docutils.parsers import rst
 from docutils.readers import standalone, pep
 from docutils.writers import html4css1, html5_polyglot, pep_html
@@ -36,9 +35,8 @@
 
 
 usage = '%prog [options] [<directory> ...]'
-description = ('Generates .html from all the reStructuredText .txt files '
-               '(including PEPs) in each <directory> '
-               '(default is the current directory).')
+description = ('Generate .html from all reStructuredText files '
+               'in each <directory> (default is the current directory).')
 
 
 class SettingsSpec(docutils.SettingsSpec):
@@ -47,7 +45,9 @@
     Runtime settings & command-line options for the "buildhtml" front end.
     """
 
-    prune_default = ['.hg', '.bzr', '.git', '.svn', 'CVS']
+    prune_default = ['/*/.hg', '/*/.bzr', '/*/.git', '/*/.svn',
+                     '/*/.venv', '/*/__pycache__']
+    rst_sources_default = ['*.rst', '*.txt']
 
     # Can't be included in OptionParser below because we don't want to
     # override the base class.
@@ -61,16 +61,25 @@
            'validator': frontend.validate_boolean}),
          ('Do not scan subdirectories for files to process.',
           ['--local'], {'dest': 'recurse', 'action': 'store_false'}),
-         ('Do not process files in <directory> (shell globbing patterns, '
+         ('Do not process files in <directory> (glob-style patterns, '
           'separated by colons).  This option may be used '
-          'more than once to specify multiple directories.  Default: "%s".'
+          'more than once to add more patterns.  Default: "%s".'
           % ':'.join(prune_default),
           ['--prune'],
           {'metavar': '<directory>', 'action': 'append',
            'validator': frontend.validate_colon_separated_string_list,
            'default': prune_default}),
+         ('Process all files matching any of the given '
+          'glob-style patterns (separated by colons). '
+          'This option overwrites the default or config-file values. '
+          f'Default: "{":".join(rst_sources_default)}".',
+          ['--rst-sources'],
+          {'metavar': '<patterns>',
+           'default': rst_sources_default,
+           'validator': frontend.validate_colon_separated_string_list}),
          ('Recursively ignore files matching any of the given '
-          'wildcard (shell globbing) patterns (separated by colons).',
+          'glob-style patterns (separated by colons). '
+          'This option may be used more than once to add more patterns.',
           ['--ignore'],
           {'metavar': '<patterns>', 'action': 'append',
            'default': [],
@@ -191,7 +200,11 @@
 
         Copy the setting defaults, overlay the startup config file settings,
         then the local config file settings, then the command-line options.
-        Assumes the current directory has been set.
+
+        If `directory` is not None, it is searched for a file "docutils.conf"
+        which is parsed after standard configuration files.
+        Path settings in this configuration file are resolved relative
+        to `directory`, not the current working directory.
         """
         publisher = self.publishers[publisher_name]
         with warnings.catch_warnings():
@@ -206,9 +219,12 @@
                 directory)
             settings.update(local_config, publisher.option_parser)
         settings.update(self.settings_spec.__dict__, publisher.option_parser)
+        # remove duplicate entries from "appending" settings:
+        settings.ignore = list(set(settings.ignore))
+        settings.prune = list(set(settings.prune))
         return settings
 
-    def run(self, directory=None, recurse=1):
+    def run(self, directory=None, recurse=True):
         recurse = recurse and self.initial_settings.recurse
         if directory:
             self.directories = [directory]
@@ -217,37 +233,37 @@
         else:
             self.directories = [os.getcwd()]
         for directory in self.directories:
-            for root, dirs, files in os.walk(directory):
-                # os.walk by default this recurses down the tree,
-                # influence by modifying dirs.
-                if not recurse:
-                    del dirs[:]
-                self.visit(root, files, dirs)
+            directory = os.path.abspath(directory)
+            for dirpath, dirnames, filenames in os.walk(directory):
+                # `os.walk()` by default recurses down the tree,
+                # we modify `dirnames` in-place to control the behaviour.
+                if recurse:
+                    dirnames.sort()
+                else:
+                    del dirnames[:]
+                self.visit(dirpath, dirnames, filenames)
 
-    def visit(self, directory, names, subdirectories):
-        settings = self.get_settings('', directory)
+    def visit(self, dirpath, dirnames, filenames):
+        settings = self.get_settings('', dirpath)
         errout = docutils.io.ErrorOutput(encoding=settings.error_encoding)
-        if settings.prune and (os.path.abspath(directory) in settings.prune):
-            errout.write('/// ...Skipping directory (pruned): %s\n' %
-                         directory)
+        if match_patterns(dirpath, settings.prune):
+            errout.write('/// ...Skipping directory (pruned): %s\n'
+                         % os.path.relpath(dirpath))
             sys.stderr.flush()
-            del subdirectories[:]
+            del dirnames[:]  # modify in-place to control `os.walk()` run
             return
         if not self.initial_settings.silent:
-            errout.write('/// Processing directory: %s\n' % directory)
+            errout.write('/// Processing directory: %s\n'
+                         % os.path.relpath(dirpath))
             sys.stderr.flush()
-        # settings.ignore grows many duplicate entries as we recurse
-        # if we add patterns in config files or on the command line.
-        for pattern in utils.uniq(settings.ignore):
-            for i in range(len(names) - 1, -1, -1):
-                if fnmatch(names[i], pattern):
-                    # Modify in place!
-                    del names[i]
-        for name in names:
-            if name.endswith('.txt'):
-                self.process_txt(directory, name)
+        for name in sorted(filenames):
+            if match_patterns(name, settings.ignore):
+                continue
+            if match_patterns(name, settings.rst_sources):
+                self.process_txt(dirpath, name)
 
     def process_txt(self, directory, name):
+        # TODO change name to `process_rst_source_file()`?
         if name.startswith('pep-'):
             publisher = 'PEPs'
         else:
@@ -256,7 +272,7 @@
         errout = docutils.io.ErrorOutput(encoding=settings.error_encoding)
         pub_struct = self.publishers[publisher]
         settings._source = os.path.normpath(os.path.join(directory, name))
-        settings._destination = settings._source[:-4] + '.html'
+        settings._destination = os.path.splitext(settings._source)[0] + '.html'
         if not self.initial_settings.silent:
             errout.write('    ::: Processing: %s\n' % name)
             sys.stderr.flush()
@@ -272,5 +288,22 @@
                 errout.write(f'        {type(err).__name__}: {err}\n')
 
 
+def match_patterns(name, patterns):
+    """Return True, if `name` matches any item of the sequence `patterns`.
+
+    Matching is done with `fnmatch.fnmatch`. It resembles shell-style
+    globbing, but without special treatment of path separators and '.'
+    (in contrast to the `glob module` and `pathlib.PurePath.match()`).
+    For example, "``/*.py``" matches "/a/b/c.py".
+
+    PROVISIONAL.
+    TODO: use `pathlib.PurePath.match()` once this supports "**".
+    """
+    for pattern in patterns:
+        if fnmatch(name, pattern):
+            return True
+    return False
+
+
 if __name__ == "__main__":
     Builder().run()

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.