![](https://seccdn.libravatar.org/avatar/e2145bc5cf53dda95c308a3c75e8fef3.jpg?s=120&d=mm&r=g)
Hello community, here is the log from the commit of package rstcheck for openSUSE:Factory checked in at 2017-06-24 08:34:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rstcheck (Old) and /work/SRC/openSUSE:Factory/.rstcheck.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "rstcheck" Sat Jun 24 08:34:41 2017 rev:3 rq:505844 version:3.1 Changes: -------- --- /work/SRC/openSUSE:Factory/rstcheck/rstcheck.changes 2016-07-14 09:50:28.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rstcheck.new/rstcheck.changes 2017-06-24 08:34:58.064032837 +0200 @@ -1,0 +2,12 @@ +Fri Jun 16 08:16:09 UTC 2017 - jhura@suse.com + +- bump to verion 3.1 +- Add support for checking XML code blocks (thanks to Sameer Singh). +- Support UTF-8 byte order marks (BOM). Previously, ``docutils`` would + interpret the BOM as a visible character, which would lead to false + positives about underlines being too short. +- Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is + installed. +- Support loading settings from configuration files. + +------------------------------------------------------------------- Old: ---- rstcheck-1.5.1.tar.gz New: ---- rstcheck-3.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rstcheck.spec ++++++ --- /var/tmp/diff_new_pack.TlvQu4/_old 2017-06-24 08:34:58.523967802 +0200 +++ /var/tmp/diff_new_pack.TlvQu4/_new 2017-06-24 08:34:58.523967802 +0200 @@ -1,7 +1,7 @@ # # spec file for package rstcheck # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,20 +17,19 @@ Name: rstcheck -Version: 1.5.1 +Version: 3.1 Release: 0 Summary: Checks syntax of rST and code blocks nested within it License: MIT Group: Development/Languages/Python Url: https://github.com/myint/rstcheck -Source: http://pypi.python.org/packages/source/r/rstcheck/rstcheck-%{version}.tar.gz +Source: https://files.pythonhosted.org/packages/source/r/rstcheck/rstcheck-%{version}.tar.gz BuildRequires: python3-Sphinx BuildRequires: python3-devel BuildRequires: python3-docutils BuildRequires: python3-setuptools Requires: python3-Sphinx Requires: python3-docutils -BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildArch: noarch %description ++++++ rstcheck-1.5.1.tar.gz -> rstcheck-3.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/LICENSE new/rstcheck-3.1/LICENSE --- old/rstcheck-1.5.1/LICENSE 2015-08-16 20:15:34.000000000 +0200 +++ new/rstcheck-3.1/LICENSE 2016-07-24 23:24:23.000000000 +0200 @@ -1,4 +1,4 @@ -Copyright (C) 2013-2015 Steven Myint +Copyright (C) 2013-2016 Steven Myint Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/PKG-INFO new/rstcheck-3.1/PKG-INFO --- old/rstcheck-1.5.1/PKG-INFO 2016-03-29 17:13:30.000000000 +0200 +++ new/rstcheck-3.1/PKG-INFO 2017-03-08 17:00:34.000000000 +0100 @@ -1,7 +1,7 @@ Metadata-Version: 1.1 Name: rstcheck -Version: 1.5.1 -Summary: Checks syntax of reStructuredText and code blocks nested within it. +Version: 3.1 +Summary: Checks syntax of reStructuredText and code blocks nested within it Home-page: https://github.com/myint/rstcheck Author: UNKNOWN Author-email: UNKNOWN @@ -17,12 +17,15 @@ Checks syntax of reStructuredText and code blocks nested within it. + .. contents:: + + Installation ============ From pip:: - $ pip install --upgrade rstcheck + $ pip install rstcheck Supported languages in code blocks @@ -33,6 +36,7 @@ - C (C99) - C++ (C++11) - JSON + - XML - Python - reStructuredText @@ -42,13 +46,13 @@ With bad Python syntax: - .. code-block:: rst + .. code:: rst ==== Test ==== - .. code-block:: python + .. code:: python print( @@ -59,13 +63,13 @@ With bad C++ syntax: - .. code-block:: rst + .. code:: rst ==== Test ==== - .. code-block:: cpp + .. code:: cpp int main() { @@ -79,7 +83,7 @@ With bad syntax in the reStructuredText document itself: - .. code-block:: rst + .. code:: rst ==== Test @@ -175,12 +179,26 @@ $ rstcheck docs/foo/bar.rst + Sphinx + ====== + + To enable Sphinx:: + + $ pip install sphinx + + The installed Sphinx version must be at least 1.5. + + To check that Sphinx support is enabled:: + + $ rstcheck -h | grep 'Sphinx is enabled' + + Usage in Vim ============ To check reStructuredText in Vim using Syntastic_: - .. code-block:: vim + .. code:: vim let g:syntastic_rst_checkers = ['rstcheck'] @@ -200,6 +218,44 @@ Note that this does not load any configuration as that would mutate the ``docutils`` registries. + + History + ======= + + 3.1 (2017-03-08) + ---------------- + + - Add support for checking XML code blocks (thanks to Sameer Singh). + + 3.0.1 (2017-03-01) + ------------------ + + - Support UTF-8 byte order marks (BOM). Previously, ``docutils`` would + interpret the BOM as a visible character, which would lead to false positives + about underlines being too short. + + 3.0 (2016-12-19) + ---------------- + + - Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is + installed. + + 2.0 (2015-07-27) + ---------------- + + - Support loading settings from configuration files. + + 1.0 (2015-03-14) + ---------------- + + - Add Sphinx support. + + 0.1 (2013-12-02) + ---------------- + + - Initial version. + + .. rstcheck: ignore-language=cpp,python,rst Keywords: restructuredtext,lint,check,pypi,readme,rst,analyze @@ -211,4 +267,5 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Quality Assurance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/README.rst new/rstcheck-3.1/README.rst --- old/rstcheck-1.5.1/README.rst 2016-01-24 19:36:55.000000000 +0100 +++ new/rstcheck-3.1/README.rst 2017-03-08 16:59:53.000000000 +0100 @@ -9,12 +9,15 @@ Checks syntax of reStructuredText and code blocks nested within it. +.. contents:: + + Installation ============ From pip:: - $ pip install --upgrade rstcheck + $ pip install rstcheck Supported languages in code blocks @@ -25,6 +28,7 @@ - C (C99) - C++ (C++11) - JSON +- XML - Python - reStructuredText @@ -34,13 +38,13 @@ With bad Python syntax: -.. code-block:: rst +.. code:: rst ==== Test ==== - .. code-block:: python + .. code:: python print( @@ -51,13 +55,13 @@ With bad C++ syntax: -.. code-block:: rst +.. code:: rst ==== Test ==== - .. code-block:: cpp + .. code:: cpp int main() { @@ -71,7 +75,7 @@ With bad syntax in the reStructuredText document itself: -.. code-block:: rst +.. code:: rst ==== Test @@ -167,12 +171,26 @@ $ rstcheck docs/foo/bar.rst +Sphinx +====== + +To enable Sphinx:: + + $ pip install sphinx + +The installed Sphinx version must be at least 1.5. + +To check that Sphinx support is enabled:: + + $ rstcheck -h | grep 'Sphinx is enabled' + + Usage in Vim ============ To check reStructuredText in Vim using Syntastic_: -.. code-block:: vim +.. code:: vim let g:syntastic_rst_checkers = ['rstcheck'] @@ -192,4 +210,42 @@ Note that this does not load any configuration as that would mutate the ``docutils`` registries. + +History +======= + +3.1 (2017-03-08) +---------------- + +- Add support for checking XML code blocks (thanks to Sameer Singh). + +3.0.1 (2017-03-01) +------------------ + +- Support UTF-8 byte order marks (BOM). Previously, ``docutils`` would + interpret the BOM as a visible character, which would lead to false positives + about underlines being too short. + +3.0 (2016-12-19) +---------------- + +- Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is + installed. + +2.0 (2015-07-27) +---------------- + +- Support loading settings from configuration files. + +1.0 (2015-03-14) +---------------- + +- Add Sphinx support. + +0.1 (2013-12-02) +---------------- + +- Initial version. + + .. rstcheck: ignore-language=cpp,python,rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/rstcheck.egg-info/PKG-INFO new/rstcheck-3.1/rstcheck.egg-info/PKG-INFO --- old/rstcheck-1.5.1/rstcheck.egg-info/PKG-INFO 2016-03-29 17:13:30.000000000 +0200 +++ new/rstcheck-3.1/rstcheck.egg-info/PKG-INFO 2017-03-08 17:00:33.000000000 +0100 @@ -1,7 +1,7 @@ Metadata-Version: 1.1 Name: rstcheck -Version: 1.5.1 -Summary: Checks syntax of reStructuredText and code blocks nested within it. +Version: 3.1 +Summary: Checks syntax of reStructuredText and code blocks nested within it Home-page: https://github.com/myint/rstcheck Author: UNKNOWN Author-email: UNKNOWN @@ -17,12 +17,15 @@ Checks syntax of reStructuredText and code blocks nested within it. + .. contents:: + + Installation ============ From pip:: - $ pip install --upgrade rstcheck + $ pip install rstcheck Supported languages in code blocks @@ -33,6 +36,7 @@ - C (C99) - C++ (C++11) - JSON + - XML - Python - reStructuredText @@ -42,13 +46,13 @@ With bad Python syntax: - .. code-block:: rst + .. code:: rst ==== Test ==== - .. code-block:: python + .. code:: python print( @@ -59,13 +63,13 @@ With bad C++ syntax: - .. code-block:: rst + .. code:: rst ==== Test ==== - .. code-block:: cpp + .. code:: cpp int main() { @@ -79,7 +83,7 @@ With bad syntax in the reStructuredText document itself: - .. code-block:: rst + .. code:: rst ==== Test @@ -175,12 +179,26 @@ $ rstcheck docs/foo/bar.rst + Sphinx + ====== + + To enable Sphinx:: + + $ pip install sphinx + + The installed Sphinx version must be at least 1.5. + + To check that Sphinx support is enabled:: + + $ rstcheck -h | grep 'Sphinx is enabled' + + Usage in Vim ============ To check reStructuredText in Vim using Syntastic_: - .. code-block:: vim + .. code:: vim let g:syntastic_rst_checkers = ['rstcheck'] @@ -200,6 +218,44 @@ Note that this does not load any configuration as that would mutate the ``docutils`` registries. + + History + ======= + + 3.1 (2017-03-08) + ---------------- + + - Add support for checking XML code blocks (thanks to Sameer Singh). + + 3.0.1 (2017-03-01) + ------------------ + + - Support UTF-8 byte order marks (BOM). Previously, ``docutils`` would + interpret the BOM as a visible character, which would lead to false positives + about underlines being too short. + + 3.0 (2016-12-19) + ---------------- + + - Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is + installed. + + 2.0 (2015-07-27) + ---------------- + + - Support loading settings from configuration files. + + 1.0 (2015-03-14) + ---------------- + + - Add Sphinx support. + + 0.1 (2013-12-02) + ---------------- + + - Initial version. + + .. rstcheck: ignore-language=cpp,python,rst Keywords: restructuredtext,lint,check,pypi,readme,rst,analyze @@ -211,4 +267,5 @@ Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Quality Assurance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/rstcheck.egg-info/requires.txt new/rstcheck-3.1/rstcheck.egg-info/requires.txt --- old/rstcheck-1.5.1/rstcheck.egg-info/requires.txt 2016-03-29 17:13:30.000000000 +0200 +++ new/rstcheck-3.1/rstcheck.egg-info/requires.txt 2017-03-08 17:00:33.000000000 +0100 @@ -1,2 +1 @@ -docutils -sphinx +docutils >= 0.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/rstcheck.py new/rstcheck-3.1/rstcheck.py --- old/rstcheck-1.5.1/rstcheck.py 2016-03-29 17:12:36.000000000 +0200 +++ new/rstcheck-3.1/rstcheck.py 2017-03-08 16:57:21.000000000 +0100 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (C) 2013-2015 Steven Myint +# Copyright (C) 2013-2016 Steven Myint # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -37,9 +37,11 @@ import multiprocessing import os import re +import shutil import subprocess import sys import tempfile +from xml.etree import ElementTree try: import configparser @@ -53,24 +55,36 @@ import docutils.utils import docutils.writers -import sphinx -import sphinx.directives -import sphinx.domains.c -import sphinx.domains.cpp -import sphinx.domains.javascript -import sphinx.domains.python -import sphinx.domains.std -import sphinx.roles +try: + import sphinx + SPHINX_INSTALLED = sphinx.version_info >= (1, 5) +except ImportError: + SPHINX_INSTALLED = False +if SPHINX_INSTALLED: + import sphinx.application + import sphinx.directives + import sphinx.domains.c + import sphinx.domains.cpp + import sphinx.domains.javascript + import sphinx.domains.python + import sphinx.domains.std + import sphinx.roles -__version__ = '1.5.1' +__version__ = '3.1' -SPHINX_CODE_BLOCK_DELTA = -1 if sphinx.version_info >= (1, 3) else 0 + +if SPHINX_INSTALLED: + SPHINX_CODE_BLOCK_DELTA = -1 RSTCHECK_COMMENT_RE = re.compile(r'\.\. rstcheck:') +# This is for the cases where code in a readme uses includes in that directory. +INCLUDE_FLAGS = ['-I.', '-I..'] + + class Error(Exception): """rstcheck exception.""" @@ -80,6 +94,45 @@ Exception.__init__(self, message) +class CodeBlockDirective(docutils.parsers.rst.Directive): + + """Code block directive.""" + + has_content = True + optional_arguments = 1 + + def run(self): + """Run directive.""" + try: + language = self.arguments[0] + except IndexError: + language = '' + code = '\n'.join(self.content) + literal = docutils.nodes.literal_block(code, code) + literal['classes'].append('code-block') + literal['language'] = language + return [literal] + + +def register_code_directive(): + """Register code directive.""" + if not SPHINX_INSTALLED: + docutils.parsers.rst.directives.register_directive('code', + CodeBlockDirective) + docutils.parsers.rst.directives.register_directive('code-block', + CodeBlockDirective) + docutils.parsers.rst.directives.register_directive('sourcecode', + CodeBlockDirective) + + +def strip_byte_order_mark(text): + """Return text with byte order mark (BOM) removed.""" + try: + return text.encode('utf-8').decode('utf-8-sig') + except UnicodeError: + return text + + def check(source, filename='<string>', report_level=docutils.utils.Reporter.INFO_LEVEL, @@ -98,6 +151,11 @@ Each code block is checked asynchronously in a subprocess. """ + # Do this at call time rather than import time to avoid unnecessarily + # mutating state. + register_code_directive() + ignore_sphinx() + ignore = ignore or [] try: @@ -109,6 +167,11 @@ string_io = io.StringIO() + # This is a hack to avoid false positive from docutils (#23). docutils + # mistakes BOMs for actual visible letters. This results in the "underline + # too short" warning firing. + source = strip_byte_order_mark(source) + try: docutils.core.publish_string( source, writer=writer, @@ -185,7 +248,7 @@ ignore_from_config(os.path.dirname(os.path.realpath(filename))) ignore_directives_and_roles(args.ignore_directives, args.ignore_roles) - ignore_sphinx() + for substitution in args.ignore_substitutions: contents = contents.replace('|{}|'.format(substitution), 'None') @@ -222,6 +285,21 @@ yield (int(line_number), message) +def check_xml(code): + """Yield errors.""" + try: + ElementTree.fromstring(code) + except ElementTree.ParseError as exception: + message = '{}'.format(exception) + line_number = 0 + + found = re.search(r': line\s+([0-9]+)[^:]*$', message) + if found: + line_number = int(found.group(1)) + + yield (int(line_number), message) + + def check_rst(code, ignore): """Yield errors in nested RST code.""" filename = '<string>' @@ -263,16 +341,6 @@ directives = get_and_split(options, 'ignore_directives') roles = get_and_split(options, 'ignore_roles') - # Deprecated since 1.3. - try: - roles = split_comma_separated(parser.get('roles', 'ignore')) - except (configparser.NoOptionError, configparser.NoSectionError): - pass - try: - directives = split_comma_separated(parser.get('directives', 'ignore')) - except (configparser.NoOptionError, configparser.NoSectionError): - pass - return (directives, roles) @@ -288,21 +356,71 @@ def _get_directives_and_roles_from_sphinx(): """Return a tuple of Sphinx directive and roles.""" - sphinx_directives = list(sphinx.domains.std.StandardDomain.directives) - sphinx_roles = list(sphinx.domains.std.StandardDomain.roles) - - for domain in [sphinx.domains.c.CDomain, - sphinx.domains.cpp.CPPDomain, - sphinx.domains.javascript.JavaScriptDomain, - sphinx.domains.python.PythonDomain]: - - sphinx_directives += list(domain.directives) + [ - '{}:{}'.format(domain.name, item) - for item in list(domain.directives)] - - sphinx_roles += list(domain.roles) + [ - '{}:{}'.format(domain.name, item) - for item in list(domain.roles)] + if SPHINX_INSTALLED: + sphinx_directives = list(sphinx.domains.std.StandardDomain.directives) + sphinx_roles = list(sphinx.domains.std.StandardDomain.roles) + + for domain in [sphinx.domains.c.CDomain, + sphinx.domains.cpp.CPPDomain, + sphinx.domains.javascript.JavaScriptDomain, + sphinx.domains.python.PythonDomain]: + + sphinx_directives += list(domain.directives) + [ + '{}:{}'.format(domain.name, item) + for item in list(domain.directives)] + + sphinx_roles += list(domain.roles) + [ + '{}:{}'.format(domain.name, item) + for item in list(domain.roles)] + else: + sphinx_roles = [ + 'abbr', + 'command', + 'dfn', + 'doc', + 'download', + 'envvar', + 'file', + 'guilabel', + 'kbd', + 'keyword', + 'mailheader', + 'makevar', + 'manpage', + 'menuselection', + 'mimetype', + 'newsgroup', + 'option', + 'program', + 'py:func', + 'ref', + 'regexp', + 'samp', + 'term', + 'token'] + + sphinx_directives = [ + 'autosummary', + 'currentmodule', + 'centered', + 'c:function', + 'c:type', + 'include', + 'deprecated', + 'envvar', + 'glossary', + 'index', + 'no-code-block', + 'literalinclude', + 'hlist', + 'option', + 'productionlist', + 'py:function', + 'seealso', + 'toctree', + 'todo', + 'versionadded', + 'versionchanged'] return (sphinx_directives, sphinx_roles) @@ -425,14 +543,15 @@ def c_checker(code, working_directory): """Return checker.""" - return gcc_checker(code, '.c', [os.getenv('CC', 'gcc'), '-std=c99', '-I.'], + return gcc_checker(code, '.c', + [os.getenv('CC', 'gcc'), '-std=c99'] + INCLUDE_FLAGS, working_directory=working_directory) def cpp_checker(code, working_directory): """Return checker.""" - return gcc_checker(code, '.cpp', [os.getenv('CXX', 'g++'), '-std=c++0x', - '-I.'], + return gcc_checker(code, '.cpp', + [os.getenv('CXX', 'g++'), '-std=c++0x'] + INCLUDE_FLAGS, working_directory=working_directory) @@ -523,11 +642,23 @@ self._add_check(node=node, run=lambda: check_doctest(node.rawsource), - language='doctest') + language='doctest', + is_code_node=False) def visit_literal_block(self, node): """Check syntax of code block.""" + # For "..code-block:: language" language = node.get('language', None) + is_code_node = False + if not language: + # For "..code:: language" + is_code_node = True + classes = node.get('classes') + if 'code' in classes: + language = classes[-1] + else: + return + if language in self.ignore: return @@ -542,6 +673,7 @@ 'c': c_checker, 'cpp': cpp_checker, 'json': lambda source, _: lambda: check_json(source), + 'xml': lambda source, _: lambda: check_xml(source), 'python': lambda source, _: lambda: check_python(source), 'rst': lambda source, _: lambda: check_rst(source, ignore=self.ignore) @@ -549,11 +681,14 @@ if checker: run = checker(node.rawsource, self.working_directory) - self._add_check(node=node, run=run, language=language) + self._add_check(node=node, + run=run, + language=language, + is_code_node=is_code_node) raise docutils.nodes.SkipNode - def _add_check(self, node, run, language): + def _add_check(self, node, run, language, is_code_node): """Add checker that will be run.""" def run_check(): """Yield errors.""" @@ -563,14 +698,16 @@ for result in all_results: error_offset = result[0] - 1 - try: + line_number = getattr(node, 'line', None) + if line_number is not None: yield ( - beginning_of_code_block(node, self.contents) + + beginning_of_code_block( + node=node, + line_number=line_number, + full_contents=self.contents, + is_code_node=is_code_node) + error_offset, '({}) {}'.format(language, result[1])) - except TypeError: - # Ignore case where node's line_number is None. - pass else: yield (self.filename, 0, 'unknown error') self.checkers.append(run_check) @@ -582,14 +719,37 @@ """Ignore.""" -def beginning_of_code_block(node, full_contents): +def beginning_of_code_block(node, line_number, full_contents, is_code_node): """Return line number of beginning of code block.""" - line_number = node.line - delta = len(node.non_default_attributes()) - current_line_contents = full_contents.splitlines()[line_number:] - blank_lines = next((i for (i, x) in enumerate(current_line_contents) if x), - 0) - return line_number + delta - 1 + blank_lines - 1 + SPHINX_CODE_BLOCK_DELTA + if SPHINX_INSTALLED and not is_code_node: + delta = len(node.non_default_attributes()) + current_line_contents = full_contents.splitlines()[line_number:] + blank_lines = next( + (i for (i, x) in enumerate(current_line_contents) if x), + 0) + return ( + line_number + + delta - 1 + + blank_lines - 1 + + SPHINX_CODE_BLOCK_DELTA) + else: + lines = full_contents.splitlines() + code_block_length = len(node.rawsource.splitlines()) + + try: + # Case where there are no extra spaces. + if lines[line_number - 1].strip(): + return line_number - code_block_length + 1 + except IndexError: + pass + + # The offsets are wrong if the RST text has multiple blank lines after + # the code block. This is a workaround. + for line_number in range(line_number, 1, -1): + if lines[line_number - 2].strip(): + break + + return line_number - code_block_length class CheckWriter(docutils.writers.Writer): @@ -625,7 +785,11 @@ """Return parsed command-line arguments.""" threshold_choices = docutils.frontend.OptionParser.threshold_choices - parser = argparse.ArgumentParser(description=__doc__, prog='rstcheck') + parser = argparse.ArgumentParser( + description=__doc__ + (' Sphinx is enabled.' + if SPHINX_INSTALLED else ''), + prog='rstcheck') + parser.add_argument('files', nargs='+', type=decode_filename, help='files to check') parser.add_argument('--report', metavar='level', @@ -649,9 +813,10 @@ metavar='roles', default='', help='comma-separated list of roles to ignore') parser.add_argument('--debug', action='store_true', - help='show helpful for debugging') + help='show messages helpful for debugging') parser.add_argument('--version', action='version', version='%(prog)s ' + __version__) + args = parser.parse_args() if '-' in args.files and len(args.files) > 1: @@ -681,42 +846,62 @@ print(text, file=file) +@contextlib.contextmanager +def enable_sphinx_if_possible(): + """Register Sphinx directives and roles.""" + if SPHINX_INSTALLED: + temporary_directory = tempfile.mkdtemp() + try: + sphinx.application.Sphinx(srcdir=temporary_directory, + confdir=None, + outdir=temporary_directory, + doctreedir=temporary_directory, + buildername='dummy', + status=None) + yield + finally: + shutil.rmtree(temporary_directory) + else: + yield + + def main(): """Return 0 on success.""" args = parse_args() - status = 0 - pool = multiprocessing.Pool(multiprocessing.cpu_count()) - try: - if len(args.files) > 1: - # Run in separate process to avoid mutating the global docutils - # settings based on the local configuration. It also avoids - # mutating the settings when rstcheck is used as a module. - results = pool.map( - _check_file, - [(name, args) for name in args.files]) - else: - # This is for the case where we read from standard in. - results = [_check_file((args.files[0], args))] - - for (filename, errors) in results: - for error in errors: - line_number = error[0] - message = error[1] - - if not re.match(r'\([A-Z]+/[0-9]+\)', message): - message = '(ERROR/3) ' + message - - output_message('{}:{}: {}'.format(filename, - line_number, - message)) - - status = 1 - except IOError as exception: - output_message(exception) - status = 1 + with enable_sphinx_if_possible(): + status = 0 + pool = multiprocessing.Pool(multiprocessing.cpu_count()) + try: + if len(args.files) > 1: + # Run in separate process to avoid mutating the global docutils + # settings based on the local configuration. It also avoids + # mutating the settings when rstcheck is used as a module. + results = pool.map( + _check_file, + [(name, args) for name in args.files]) + else: + # This is for the case where we read from standard in. + results = [_check_file((args.files[0], args))] + + for (filename, errors) in results: + for error in errors: + line_number = error[0] + message = error[1] + + if not re.match(r'\([A-Z]+/[0-9]+\)', message): + message = '(ERROR/3) ' + message + + output_message('{}:{}: {}'.format(filename, + line_number, + message)) + + status = 1 + except (IOError, UnicodeError) as exception: + output_message(exception) + status = 1 - return status + return status if __name__ == '__main__': diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/setup.cfg new/rstcheck-3.1/setup.cfg --- old/rstcheck-1.5.1/setup.cfg 2016-03-29 17:13:30.000000000 +0200 +++ new/rstcheck-3.1/setup.cfg 2017-03-08 17:00:34.000000000 +0100 @@ -1,5 +1,5 @@ [egg_info] -tag_svn_revision = 0 tag_build = tag_date = 0 +tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/rstcheck-1.5.1/setup.py new/rstcheck-3.1/setup.py --- old/rstcheck-1.5.1/setup.py 2015-09-18 16:58:09.000000000 +0200 +++ new/rstcheck-3.1/setup.py 2017-01-29 17:31:19.000000000 +0100 @@ -22,7 +22,7 @@ version=version(), url='https://github.com/myint/rstcheck', description='Checks syntax of reStructuredText and code blocks nested ' - 'within it.', + 'within it', long_description=readme.read(), classifiers=[ 'License :: OSI Approved :: MIT License', @@ -32,10 +32,10 @@ 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Quality Assurance', ], keywords='restructuredtext,lint,check,pypi,readme,rst,analyze', py_modules=['rstcheck'], entry_points={'console_scripts': ['rstcheck = rstcheck:main']}, - install_requires=['docutils', 'sphinx'] - ) + install_requires=['docutils >= 0.7'])