From 57d1e9afc9aa04fbf999f0d2fddd03d8901b6c5d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 12 Jul 2019 13:47:24 +0100 Subject: [PATCH] Project Migration to PyCQA This change rehomes the project to PyCQA [1] as reported to the openstack-dev mailing list [2]. [1] https://mail.python.org/pipermail/code-quality/2019-July/001112.html [2] http://lists.openstack.org/pipermail/openstack-discuss/2019-July/007878.html Change-Id: I5472bea4994664495220ee4ab565f95666f21eee Signed-off-by: Stephen Finucane Depends-On: I740c66cd959db1efa8ca8c9f29d4da4b66fbd993 --- .gitignore | 54 ----- .gitreview | 4 +- CONTRIBUTING.rst | 15 -- HACKING.rst | 4 - LICENSE | 201 ------------------- MANIFEST.in | 6 - README.rst | 137 +------------ doc/source/conf.py | 70 ------- doc/source/contributing.rst | 4 - doc/source/index.rst | 20 -- doc/source/installation.rst | 12 -- doc/source/readme.rst | 1 - doc/source/usage.rst | 7 - doc8/__init__.py | 0 doc8/checks.py | 302 ---------------------------- doc8/main.py | 382 ------------------------------------ doc8/parser.py | 144 -------------- doc8/tests/__init__.py | 0 doc8/tests/test_checks.py | 191 ------------------ doc8/utils.py | 77 -------- doc8/version.py | 24 --- pylintrc | 31 --- requirements.txt | 9 - setup.cfg | 33 ---- setup.py | 30 --- test-requirements.txt | 10 - tox.ini | 32 --- 27 files changed, 10 insertions(+), 1790 deletions(-) delete mode 100644 .gitignore delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 MANIFEST.in delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/readme.rst delete mode 100644 doc/source/usage.rst delete mode 100644 doc8/__init__.py delete mode 100644 doc8/checks.py delete mode 100644 doc8/main.py delete mode 100644 doc8/parser.py delete mode 100644 doc8/tests/__init__.py delete mode 100644 doc8/tests/test_checks.py delete mode 100644 doc8/utils.py delete mode 100644 doc8/version.py delete mode 100644 pylintrc delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100755 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 320bdff..0000000 --- a/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -bin/ -build/ -develop-eggs/ -dist/ -eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.cache -nosetests.xml -coverage.xml - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Rope -.ropeproject - -# Django stuff: -*.log -*.pot - -# Sphinx documentation -doc/build/ - diff --git a/.gitreview b/.gitreview index 5145876..3ec5f93 100644 --- a/.gitreview +++ b/.gitreview @@ -1,4 +1,4 @@ [gerrit] -host=review.openstack.org +host=review.opendev.org port=29418 -project=openstack/doc8.git +project=x/doc8.git diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 5d73ec4..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,15 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. -You can report the bugs at launchpad. - - https://bugs.launchpad.net/doc8 diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index b889622..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -doc8 Style Commandments -=============================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ad410e1..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ -Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 762d33b..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include README.rst - -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc diff --git a/README.rst b/README.rst index fb7d0ce..117fc1d 100644 --- a/README.rst +++ b/README.rst @@ -1,135 +1,14 @@ ==== -Doc8 +doc8 ==== -Doc8 is an *opinionated* style checker for `rst`_ (with basic support for -plain text) styles of documentation. +This project is no longer maintained in OpenStack. -QuickStart -========== +Please visit PyCQA to raise issues or make contributions: -:: +https://github.com/PyCQA/doc8 - pip install doc8 - -To run doc8 just invoke it against any doc directory:: - - $ doc8 coolproject/docs - -Usage -===== - -Command line usage -****************** - -:: - - $ doc8 -h - - usage: doc8 [-h] [--config path] [--allow-long-titles] [--ignore code] - [--no-sphinx] [--ignore-path path] [--ignore-path-errors path] - [--default-extension extension] [--file-encoding encoding] - [--max-line-length int] [-e extension] [-v] [--version] - [path [path ...]] - - Check documentation for simple style requirements. - - What is checked: - - invalid rst format - D000 - - lines should not be longer than 79 characters - D001 - - RST exception: line with no whitespace except in the beginning - - RST exception: lines with http or https urls - - RST exception: literal blocks - - RST exception: rst target directives - - no trailing whitespace - D002 - - no tabulation for indentation - D003 - - no carriage returns (use unix newlines) - D004 - - no newline at end of file - D005 - - positional arguments: - path Path to scan for doc files (default: current - directory). - - optional arguments: - -h, --help show this help message and exit - --config path user config file location (default: doc8.ini, tox.ini, - pep8.ini, setup.cfg). - --allow-long-titles allow long section titles (default: false). - --ignore code ignore the given error code(s). - --no-sphinx do not ignore sphinx specific false positives. - --ignore-path path ignore the given directory or file (globs are - supported). - --ignore-path-errors path - ignore the given specific errors in the provided file. - --default-extension extension - default file extension to use when a file is found - without a file extension. - --file-encoding encoding - override encoding to use when attempting to determine - an input files text encoding (providing this avoids - using `chardet` to automatically detect encoding/s) - --max-line-length int - maximum allowed line length (default: 79). - -e extension, --extension extension - check file extensions of the given type (default: - .rst, .txt). - -q, --quiet only print violations - -v, --verbose run in verbose mode. - --version show the version and exit. - -Ini file usage -************** - -Instead of using the CLI for options the following files will also be examined -for ``[doc8]`` sections that can also provided the same set of options. If -the ``--config path`` option is used these files will **not** be scanned for -the current working directory and that configuration path will be used -instead. - -* ``$CWD/doc8.ini`` -* ``$CWD/tox.ini`` -* ``$CWD/pep8.ini`` -* ``$CWD/setup.cfg`` - -An example section that can be placed into one of these files:: - - [doc8] - - ignore-path=/tmp/stuff,/tmp/other_stuff - max-line-length=99 - verbose=1 - ignore-path-errors=/tmp/other_thing.rst;D001;D002 - -**Note:** The option names are the same as the command line ones (with the -only variation of this being the ``no-sphinx`` option which from -configuration file will be ``sphinx`` instead). - -Option conflict resolution -************************** - -When the same option is passed on the command line and also via configuration -files the following strategies are applied to resolve these types -of conflicts. - -====================== =========== ======== -Option Overrides Merges -====================== =========== ======== -``allow-long-titles`` Yes No -``ignore-path-errors`` No Yes -``default-extension`` Yes No -``extension`` No Yes -``ignore-path`` No Yes -``ignore`` No Yes -``max-line-length`` Yes No -``file-encoding`` Yes No -``sphinx`` Yes No -====================== =========== ======== - -**Note:** In the above table the configuration file option when specified as -*overrides* will replace the same option given via the command line. When -*merges* is stated then the option will be combined with the command line -option (for example by becoming a larger list or set of values that contains -the values passed on the command line *and* the values passed via -configuration). - -.. _rst: http://docutils.sourceforge.net/docs/ref/rst/introduction.html +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 57e7215..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,70 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - 'oslosphinx' -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'doc8' -copyright = u'2013, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 1728a61..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,4 +0,0 @@ -============ -Contributing -============ -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 4628227..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -Welcome to doc8's documentation! -================================ - -Contents: - -.. toctree:: - :maxdepth: 2 - - readme - installation - usage - contributing - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 34667d0..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,12 +0,0 @@ -============ -Installation -============ - -At the command line:: - - $ pip install doc8 - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv doc8 - $ pip install doc8 diff --git a/doc/source/readme.rst b/doc/source/readme.rst deleted file mode 100644 index a6210d3..0000000 --- a/doc/source/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../README.rst diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index 0f8ec5d..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -===== -Usage -===== - -To use doc8 in a project:: - - import doc8 diff --git a/doc8/__init__.py b/doc8/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/doc8/checks.py b/doc8/checks.py deleted file mode 100644 index cf3a06d..0000000 --- a/doc8/checks.py +++ /dev/null @@ -1,302 +0,0 @@ -# Copyright (C) 2014 Ivan Melnikov -# -# Author: Joshua Harlow -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import collections -import re - -from docutils import nodes as docutils_nodes -import six - -from doc8 import utils - - -@six.add_metaclass(abc.ABCMeta) -class ContentCheck(object): - def __init__(self, cfg): - self._cfg = cfg - - @abc.abstractmethod - def report_iter(self, parsed_file): - pass - - -@six.add_metaclass(abc.ABCMeta) -class LineCheck(object): - def __init__(self, cfg): - self._cfg = cfg - - @abc.abstractmethod - def report_iter(self, line): - pass - - -class CheckTrailingWhitespace(LineCheck): - _TRAILING_WHITESPACE_REGEX = re.compile('\s$') - REPORTS = frozenset(["D002"]) - - def report_iter(self, line): - if self._TRAILING_WHITESPACE_REGEX.search(line): - yield ('D002', 'Trailing whitespace') - - -class CheckIndentationNoTab(LineCheck): - _STARTING_WHITESPACE_REGEX = re.compile('^(\s+)') - REPORTS = frozenset(["D003"]) - - def report_iter(self, line): - match = self._STARTING_WHITESPACE_REGEX.search(line) - if match: - spaces = match.group(1) - if '\t' in spaces: - yield ('D003', 'Tabulation used for indentation') - - -class CheckCarriageReturn(LineCheck): - REPORTS = frozenset(["D004"]) - - def report_iter(self, line): - if "\r" in line: - yield ('D004', 'Found literal carriage return') - - -class CheckNewlineEndOfFile(ContentCheck): - REPORTS = frozenset(["D005"]) - - def __init__(self, cfg): - super(CheckNewlineEndOfFile, self).__init__(cfg) - - def report_iter(self, parsed_file): - if parsed_file.lines and not parsed_file.lines[-1].endswith(b'\n'): - yield (len(parsed_file.lines), 'D005', 'No newline at end of file') - - -class CheckValidity(ContentCheck): - REPORTS = frozenset(["D000"]) - EXT_MATCHER = re.compile(r"(.*)[.]rst", re.I) - - # From docutils docs: - # - # Report system messages at or higher than : "info" or "1", - # "warning"/"2" (default), "error"/"3", "severe"/"4", "none"/"5" - # - # See: http://docutils.sourceforge.net/docs/user/config.html#report-level - WARN_LEVELS = frozenset([2, 3, 4]) - - # Only used when running in sphinx mode. - SPHINX_IGNORES_REGEX = [ - re.compile(r'^Unknown interpreted text'), - re.compile(r'^Unknown directive type'), - re.compile(r'^Undefined substitution'), - re.compile(r'^Substitution definition contains illegal element'), - ] - - def __init__(self, cfg): - super(CheckValidity, self).__init__(cfg) - self._sphinx_mode = cfg.get('sphinx') - - def report_iter(self, parsed_file): - for error in parsed_file.errors: - if error.level not in self.WARN_LEVELS: - continue - ignore = False - if self._sphinx_mode: - for m in self.SPHINX_IGNORES_REGEX: - if m.match(error.message): - ignore = True - break - if not ignore: - yield (error.line, 'D000', error.message) - - -class CheckMaxLineLength(ContentCheck): - REPORTS = frozenset(["D001"]) - - def __init__(self, cfg): - super(CheckMaxLineLength, self).__init__(cfg) - self._max_line_length = self._cfg['max_line_length'] - self._allow_long_titles = self._cfg['allow_long_titles'] - - def _extract_node_lines(self, doc): - - def extract_lines(node, start_line): - lines = [start_line] - if isinstance(node, (docutils_nodes.title)): - start = start_line - len(node.rawsource.splitlines()) - if start >= 0: - lines.append(start) - if isinstance(node, (docutils_nodes.literal_block)): - end = start_line + len(node.rawsource.splitlines()) - 1 - lines.append(end) - return lines - - def gather_lines(node): - lines = [] - for n in node.traverse(include_self=True): - lines.extend(extract_lines(n, find_line(n))) - return lines - - def find_line(node): - n = node - while n is not None: - if n.line is not None: - return n.line - n = n.parent - return None - - def filter_systems(node): - if utils.has_any_node_type(node, (docutils_nodes.system_message,)): - return False - return True - - nodes_lines = [] - first_line = -1 - for n in utils.filtered_traverse(doc, filter_systems): - line = find_line(n) - if line is None: - continue - if first_line == -1: - first_line = line - contained_lines = set(gather_lines(n)) - nodes_lines.append((n, (min(contained_lines), - max(contained_lines)))) - return (nodes_lines, first_line) - - def _extract_directives(self, lines): - - def starting_whitespace(line): - m = re.match(r"^(\s+)(.*)$", line) - if not m: - return 0 - return len(m.group(1)) - - def all_whitespace(line): - return bool(re.match(r"^(\s*)$", line)) - - def find_directive_end(start, lines): - after_lines = collections.deque(lines[start + 1:]) - k = 0 - while after_lines: - line = after_lines.popleft() - if all_whitespace(line) or starting_whitespace(line) >= 1: - k += 1 - else: - break - return start + k - - # Find where directives start & end so that we can exclude content in - # these directive regions (the rst parser may not handle this correctly - # for unknown directives, so we have to do it manually). - directives = [] - for i, line in enumerate(lines): - if re.match(r"^\s*..\s(.*?)::\s*", line): - directives.append((i, find_directive_end(i, lines))) - elif re.match(r"^::\s*$", line): - directives.append((i, find_directive_end(i, lines))) - - # Find definition terms in definition lists - # This check may match the code, which is already appended - lwhitespaces = r"^\s*" - listspattern = r"^\s*(\* |- |#\. |\d+\. )" - for i in range(0, len(lines) - 1): - line = lines[i] - next_line = lines[i + 1] - # if line is a blank, line is not a definition term - if all_whitespace(line): - continue - # if line is a list, line is checked as normal line - if re.match(listspattern, line): - continue - if (len(re.search(lwhitespaces, line).group()) < - len(re.search(lwhitespaces, next_line).group())): - directives.append((i, i)) - - return directives - - def _txt_checker(self, parsed_file): - for i, line in enumerate(parsed_file.lines_iter()): - if len(line) > self._max_line_length: - if not utils.contains_url(line): - yield (i + 1, 'D001', 'Line too long') - - def _rst_checker(self, parsed_file): - lines = list(parsed_file.lines_iter()) - doc = parsed_file.document - nodes_lines, first_line = self._extract_node_lines(doc) - directives = self._extract_directives(lines) - - def find_containing_nodes(num): - if num < first_line and len(nodes_lines): - return [nodes_lines[0][0]] - contained_in = [] - for (n, (line_min, line_max)) in nodes_lines: - if num >= line_min and num <= line_max: - contained_in.append((n, (line_min, line_max))) - smallest_span = None - best_nodes = [] - for (n, (line_min, line_max)) in contained_in: - span = line_max - line_min - if smallest_span is None: - smallest_span = span - best_nodes = [n] - elif span < smallest_span: - smallest_span = span - best_nodes = [n] - elif span == smallest_span: - best_nodes.append(n) - return best_nodes - - def any_types(nodes, types): - return any([isinstance(n, types) for n in nodes]) - - skip_types = ( - docutils_nodes.target, - docutils_nodes.literal_block, - ) - title_types = ( - docutils_nodes.title, - docutils_nodes.subtitle, - docutils_nodes.section, - ) - for i, line in enumerate(lines): - if len(line) > self._max_line_length: - in_directive = False - for (start, end) in directives: - if i >= start and i <= end: - in_directive = True - break - if in_directive: - continue - stripped = line.lstrip() - if ' ' not in stripped: - # No room to split even if we could. - continue - if utils.contains_url(stripped): - continue - nodes = find_containing_nodes(i + 1) - if any_types(nodes, skip_types): - continue - if self._allow_long_titles and any_types(nodes, title_types): - continue - yield (i + 1, 'D001', 'Line too long') - - def report_iter(self, parsed_file): - if parsed_file.extension.lower() != '.rst': - checker_func = self._txt_checker - else: - checker_func = self._rst_checker - for issue in checker_func(parsed_file): - yield issue diff --git a/doc8/main.py b/doc8/main.py deleted file mode 100644 index 9fc10e2..0000000 --- a/doc8/main.py +++ /dev/null @@ -1,382 +0,0 @@ -# Copyright (C) 2014 Ivan Melnikov -# -# Author: Joshua Harlow -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -"""Check documentation for simple style requirements. - -What is checked: - - invalid rst format - D000 - - lines should not be longer than 79 characters - D001 - - RST exception: line with no whitespace except in the beginning - - RST exception: lines with http or https urls - - RST exception: literal blocks - - RST exception: rst target directives - - no trailing whitespace - D002 - - no tabulation for indentation - D003 - - no carriage returns (use unix newlines) - D004 - - no newline at end of file - D005 -""" - -import argparse -import collections -import logging -import os -import sys - -if __name__ == '__main__': - # Only useful for when running directly (for dev/debugging). - sys.path.insert(0, os.path.abspath(os.getcwd())) - sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.getcwd()))) - -import six -from six.moves import configparser -from stevedore import extension - -from doc8 import checks -from doc8 import parser as file_parser -from doc8 import utils -from doc8 import version - -FILE_PATTERNS = ['.rst', '.txt'] -MAX_LINE_LENGTH = 79 -CONFIG_FILENAMES = [ - "doc8.ini", - "tox.ini", - "pep8.ini", - "setup.cfg", -] - - -def split_set_type(text, delimiter=","): - return set([i.strip() for i in text.split(delimiter) if i.strip()]) - - -def merge_sets(sets): - m = set() - for s in sets: - m.update(s) - return m - - -def parse_ignore_path_errors(entries): - ignore_path_errors = collections.defaultdict(set) - for path in entries: - path, ignored_errors = path.split(";", 1) - path = path.strip() - ignored_errors = split_set_type(ignored_errors, delimiter=";") - ignore_path_errors[path].update(ignored_errors) - return dict(ignore_path_errors) - - -def extract_config(args): - parser = configparser.RawConfigParser() - read_files = [] - if args['config']: - for fn in args['config']: - with open(fn, 'r') as fh: - parser.readfp(fh, filename=fn) - read_files.append(fn) - else: - read_files.extend(parser.read(CONFIG_FILENAMES)) - if not read_files: - return {} - cfg = {} - try: - cfg['max_line_length'] = parser.getint("doc8", "max-line-length") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['ignore'] = split_set_type(parser.get("doc8", "ignore")) - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['ignore_path'] = split_set_type(parser.get("doc8", - "ignore-path")) - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - ignore_path_errors = parser.get("doc8", "ignore-path-errors") - ignore_path_errors = split_set_type(ignore_path_errors) - ignore_path_errors = parse_ignore_path_errors(ignore_path_errors) - cfg['ignore_path_errors'] = ignore_path_errors - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['allow_long_titles'] = parser.getboolean("doc8", - "allow-long-titles") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['sphinx'] = parser.getboolean("doc8", "sphinx") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['verbose'] = parser.getboolean("doc8", "verbose") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['file_encoding'] = parser.get("doc8", "file-encoding") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - cfg['default_extension'] = parser.get("doc8", "default-extension") - except (configparser.NoSectionError, configparser.NoOptionError): - pass - try: - extensions = parser.get("doc8", "extensions") - extensions = extensions.split(",") - extensions = [s.strip() for s in extensions if s.strip()] - if extensions: - cfg['extension'] = extensions - except (configparser.NoSectionError, configparser.NoOptionError): - pass - return cfg - - -def fetch_checks(cfg): - base = [ - checks.CheckValidity(cfg), - checks.CheckTrailingWhitespace(cfg), - checks.CheckIndentationNoTab(cfg), - checks.CheckCarriageReturn(cfg), - checks.CheckMaxLineLength(cfg), - checks.CheckNewlineEndOfFile(cfg), - ] - mgr = extension.ExtensionManager( - namespace='doc8.extension.check', - invoke_on_load=True, - invoke_args=(cfg.copy(),), - ) - addons = [] - for e in mgr: - addons.append(e.obj) - return base + addons - - -def setup_logging(verbose): - if verbose: - level = logging.DEBUG - else: - level = logging.ERROR - logging.basicConfig(level=level, - format='%(levelname)s: %(message)s', stream=sys.stdout) - - -def scan(cfg): - if not cfg.get('quiet'): - print("Scanning...") - files = collections.deque() - ignored_paths = cfg.get('ignore_path', []) - files_ignored = 0 - file_iter = utils.find_files(cfg.get('paths', []), - cfg.get('extension', []), ignored_paths) - default_extension = cfg.get('default_extension') - file_encoding = cfg.get('file_encoding') - for filename, ignoreable in file_iter: - if ignoreable: - files_ignored += 1 - if cfg.get('verbose'): - print(" Ignoring '%s'" % (filename)) - else: - f = file_parser.parse(filename, - default_extension=default_extension, - encoding=file_encoding) - files.append(f) - if cfg.get('verbose'): - print(" Selecting '%s'" % (filename)) - return (files, files_ignored) - - -def validate(cfg, files): - if not cfg.get('quiet'): - print("Validating...") - error_counts = {} - ignoreables = frozenset(cfg.get('ignore', [])) - ignore_targeted = cfg.get('ignore_path_errors', {}) - while files: - f = files.popleft() - if cfg.get('verbose'): - print("Validating %s" % f) - targeted_ignoreables = set(ignore_targeted.get(f.filename, set())) - targeted_ignoreables.update(ignoreables) - for c in fetch_checks(cfg): - try: - # http://legacy.python.org/dev/peps/pep-3155/ - check_name = c.__class__.__qualname__ - except AttributeError: - check_name = ".".join([c.__class__.__module__, - c.__class__.__name__]) - error_counts.setdefault(check_name, 0) - try: - extension_matcher = c.EXT_MATCHER - except AttributeError: - pass - else: - if not extension_matcher.match(f.extension): - if cfg.get('verbose'): - print(" Skipping check '%s' since it does not" - " understand parsing a file with extension '%s'" - % (check_name, f.extension)) - continue - try: - reports = set(c.REPORTS) - except AttributeError: - pass - else: - reports = reports - targeted_ignoreables - if not reports: - if cfg.get('verbose'): - print(" Skipping check '%s', determined to only" - " check ignoreable codes" % check_name) - continue - if cfg.get('verbose'): - print(" Running check '%s'" % check_name) - if isinstance(c, checks.ContentCheck): - for line_num, code, message in c.report_iter(f): - if code in targeted_ignoreables: - continue - if not isinstance(line_num, (float, int)): - line_num = "?" - if cfg.get('verbose'): - print(' - %s:%s: %s %s' - % (f.filename, line_num, code, message)) - else: - print('%s:%s: %s %s' - % (f.filename, line_num, code, message)) - error_counts[check_name] += 1 - elif isinstance(c, checks.LineCheck): - for line_num, line in enumerate(f.lines_iter(), 1): - for code, message in c.report_iter(line): - if code in targeted_ignoreables: - continue - if cfg.get('verbose'): - print(' - %s:%s: %s %s' - % (f.filename, line_num, code, message)) - else: - print('%s:%s: %s %s' - % (f.filename, line_num, code, message)) - error_counts[check_name] += 1 - else: - raise TypeError("Unknown check type: %s, %s" - % (type(c), c)) - return error_counts - - -def main(): - parser = argparse.ArgumentParser( - prog='doc8', - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter) - default_configs = ", ".join(CONFIG_FILENAMES) - parser.add_argument("paths", metavar='path', type=str, nargs='*', - help=("path to scan for doc files" - " (default: current directory)."), - default=[os.getcwd()]) - parser.add_argument("--config", metavar='path', action="append", - help="user config file location" - " (default: %s)." % default_configs, - default=[]) - parser.add_argument("--allow-long-titles", action="store_true", - help="allow long section titles (default: false).", - default=False) - parser.add_argument("--ignore", action="append", metavar="code", - help="ignore the given error code(s).", - type=split_set_type, - default=[]) - parser.add_argument("--no-sphinx", action="store_false", - help="do not ignore sphinx specific false positives.", - default=True, dest='sphinx') - parser.add_argument("--ignore-path", action="append", default=[], - help="ignore the given directory or file (globs" - " are supported).", metavar='path') - parser.add_argument("--ignore-path-errors", action="append", default=[], - help="ignore the given specific errors in the" - " provided file.", metavar='path') - parser.add_argument("--default-extension", action="store", - help="default file extension to use when a file is" - " found without a file extension.", - default='', dest='default_extension', - metavar='extension') - parser.add_argument("--file-encoding", action="store", - help="override encoding to use when attempting" - " to determine an input files text encoding " - "(providing this avoids using `chardet` to" - " automatically detect encoding/s)", - default='', dest='file_encoding', - metavar='encoding') - parser.add_argument("--max-line-length", action="store", metavar="int", - type=int, - help="maximum allowed line" - " length (default: %s)." % MAX_LINE_LENGTH, - default=MAX_LINE_LENGTH) - parser.add_argument("-e", "--extension", action="append", - metavar="extension", - help="check file extensions of the given type" - " (default: %s)." % ", ".join(FILE_PATTERNS), - default=list(FILE_PATTERNS)) - parser.add_argument("-q", "--quiet", action='store_true', - help="only print violations", default=False) - parser.add_argument("-v", "--verbose", dest="verbose", action='store_true', - help="run in verbose mode.", default=False) - parser.add_argument("--version", dest="version", action='store_true', - help="show the version and exit.", default=False) - args = vars(parser.parse_args()) - if args.get('version'): - print(version.version_string()) - return 0 - args['ignore'] = merge_sets(args['ignore']) - cfg = extract_config(args) - args['ignore'].update(cfg.pop("ignore", set())) - if 'sphinx' in cfg: - args['sphinx'] = cfg.pop("sphinx") - args['extension'].extend(cfg.pop('extension', [])) - args['ignore_path'].extend(cfg.pop('ignore_path', [])) - - cfg.setdefault('ignore_path_errors', {}) - tmp_ignores = parse_ignore_path_errors(args.pop('ignore_path_errors', [])) - for path, ignores in six.iteritems(tmp_ignores): - if path in cfg['ignore_path_errors']: - cfg['ignore_path_errors'][path].update(ignores) - else: - cfg['ignore_path_errors'][path] = set(ignores) - - args.update(cfg) - setup_logging(args.get('verbose')) - - files, files_ignored = scan(args) - files_selected = len(files) - error_counts = validate(args, files) - total_errors = sum(six.itervalues(error_counts)) - - if not args.get('quiet'): - print("=" * 8) - print("Total files scanned = %s" % (files_selected)) - print("Total files ignored = %s" % (files_ignored)) - print("Total accumulated errors = %s" % (total_errors)) - if error_counts: - print("Detailed error counts:") - for check_name in sorted(six.iterkeys(error_counts)): - check_errors = error_counts[check_name] - print(" - %s = %s" % (check_name, check_errors)) - - if total_errors: - return 1 - else: - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/doc8/parser.py b/doc8/parser.py deleted file mode 100644 index 0c1c575..0000000 --- a/doc8/parser.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (C) 2014 Ivan Melnikov -# -# Author: Joshua Harlow -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import errno -import os -import threading - -import chardet -from docutils import frontend -from docutils import parsers as docutils_parser -from docutils import utils -import restructuredtext_lint as rl -import six - - -class ParsedFile(object): - FALLBACK_ENCODING = 'utf-8' - - def __init__(self, filename, encoding=None, default_extension=''): - self._filename = filename - self._content = None - self._raw_content = None - self._encoding = encoding - self._doc = None - self._errors = None - self._lines = None - self._has_read = False - self._extension = os.path.splitext(filename)[1] - self._read_lock = threading.Lock() - if not self._extension: - self._extension = default_extension - - @property - def errors(self): - if self._errors is not None: - return self._errors - self._errors = rl.lint(self.contents, filepath=self.filename) - return self._errors - - @property - def document(self): - if self._doc is None: - # Use the rst parsers document output to do as much of the - # validation as we can without resorting to custom logic (this - # parser is what sphinx and others use anyway so it's hopefully - # mature). - parser_cls = docutils_parser.get_parser_class("rst") - parser = parser_cls() - defaults = { - 'halt_level': 5, - 'report_level': 5, - 'quiet': True, - 'file_insertion_enabled': False, - 'traceback': True, - # Development use only. - 'dump_settings': False, - 'dump_internals': False, - 'dump_transforms': False, - } - opt = frontend.OptionParser(components=[parser], defaults=defaults) - doc = utils.new_document(source_path=self.filename, - settings=opt.get_default_values()) - parser.parse(self.contents, doc) - self._doc = doc - return self._doc - - def _read(self): - if self._has_read: - return - with self._read_lock: - if not self._has_read: - with open(self.filename, 'rb') as fh: - self._lines = list(fh) - fh.seek(0) - self._raw_content = fh.read() - self._has_read = True - - def lines_iter(self, remove_trailing_newline=True): - self._read() - for line in self._lines: - line = six.text_type(line, encoding=self.encoding) - if remove_trailing_newline and line.endswith("\n"): - line = line[0:-1] - yield line - - @property - def lines(self): - self._read() - return self._lines - - @property - def extension(self): - return self._extension - - @property - def filename(self): - return self._filename - - @property - def encoding(self): - if not self._encoding: - encoding = chardet.detect(self.raw_contents)['encoding'] - if not encoding: - encoding = self.FALLBACK_ENCODING - self._encoding = encoding - return self._encoding - - @property - def raw_contents(self): - self._read() - return self._raw_content - - @property - def contents(self): - if self._content is None: - self._content = six.text_type(self.raw_contents, - encoding=self.encoding) - return self._content - - def __str__(self): - return "%s (%s, %s chars, %s lines)" % ( - self.filename, self.encoding, len(self.contents), - len(list(self.lines_iter()))) - - -def parse(filename, encoding=None, default_extension=''): - if not os.path.isfile(filename): - raise IOError(errno.ENOENT, 'File not found', filename) - return ParsedFile(filename, - encoding=encoding, - default_extension=default_extension) diff --git a/doc8/tests/__init__.py b/doc8/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/doc8/tests/test_checks.py b/doc8/tests/test_checks.py deleted file mode 100644 index af32c05..0000000 --- a/doc8/tests/test_checks.py +++ /dev/null @@ -1,191 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2014 Yahoo! Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import tempfile - -import testtools - -from doc8 import checks -from doc8 import parser - - -class TestTrailingWhitespace(testtools.TestCase): - def test_trailing(self): - lines = ["a b ", "ab"] - check = checks.CheckTrailingWhitespace({}) - errors = [] - for line in lines: - errors.extend(check.report_iter(line)) - self.assertEqual(1, len(errors)) - (code, msg) = errors[0] - self.assertIn(code, check.REPORTS) - - -class TestTabIndentation(testtools.TestCase): - def test_tabs(self): - lines = [" b", "\tabc", "efg", "\t\tc"] - check = checks.CheckIndentationNoTab({}) - errors = [] - for line in lines: - errors.extend(check.report_iter(line)) - self.assertEqual(2, len(errors)) - (code, msg) = errors[0] - self.assertIn(code, check.REPORTS) - - -class TestCarriageReturn(testtools.TestCase): - def test_cr(self): - lines = ["\tabc", "efg", "\r\n"] - check = checks.CheckCarriageReturn({}) - errors = [] - for line in lines: - errors.extend(check.report_iter(line)) - self.assertEqual(1, len(errors)) - (code, msg) = errors[0] - self.assertIn(code, check.REPORTS) - - -class TestLineLength(testtools.TestCase): - def test_over_length(self): - content = b""" -=== -aaa -=== - ----- -test ----- - -""" - content += b"\n\n" - content += (b"a" * 60) + b" " + (b"b" * 60) - content += b"\n" - conf = { - 'max_line_length': 79, - 'allow_long_titles': True, - } - for ext in ['.rst', '.txt']: - with tempfile.NamedTemporaryFile(suffix=ext) as fh: - fh.write(content) - fh.flush() - - parsed_file = parser.ParsedFile(fh.name) - check = checks.CheckMaxLineLength(conf) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(1, len(errors)) - (line, code, msg) = errors[0] - self.assertIn(code, check.REPORTS) - - def test_correct_length(self): - conf = { - 'max_line_length': 79, - 'allow_long_titles': True, - } - with tempfile.NamedTemporaryFile(suffix='.rst') as fh: - fh.write(b'known exploit in the wild, for example' - b' \xe2\x80\x93 the time' - b' between advance notification') - fh.flush() - - parsed_file = parser.ParsedFile(fh.name, encoding='utf-8') - check = checks.CheckMaxLineLength(conf) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(0, len(errors)) - - def test_ignore_code_block(self): - conf = { - 'max_line_length': 79, - 'allow_long_titles': True, - } - with tempfile.NamedTemporaryFile(suffix='.rst') as fh: - fh.write(b'List which contains items with code-block\n' - b'- this is a list item\n\n' - b' .. code-block:: ini\n\n' - b' this line exceeds 80 chars but should be ignored' - b'this line exceeds 80 chars but should be ignored' - b'this line exceeds 80 chars but should be ignored') - fh.flush() - - parsed_file = parser.ParsedFile(fh.name, encoding='utf-8') - check = checks.CheckMaxLineLength(conf) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(0, len(errors)) - - def test_unsplittable_length(self): - content = b""" -=== -aaa -=== - ----- -test ----- - -""" - content += b"\n\n" - content += b"a" * 100 - content += b"\n" - conf = { - 'max_line_length': 79, - 'allow_long_titles': True, - } - # This number is different since rst parsing is aware that titles - # are allowed to be over-length, while txt parsing is not aware of - # this fact (since it has no concept of title sections). - extensions = [(0, '.rst'), (1, '.txt')] - for expected_errors, ext in extensions: - with tempfile.NamedTemporaryFile(suffix=ext) as fh: - fh.write(content) - fh.flush() - - parsed_file = parser.ParsedFile(fh.name) - check = checks.CheckMaxLineLength(conf) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(expected_errors, len(errors)) - - def test_definition_term_length(self): - conf = { - 'max_line_length': 79, - 'allow_long_titles': True, - } - with tempfile.NamedTemporaryFile(suffix='.rst') as fh: - fh.write(b'Definition List which contains long term.\n\n' - b'looooooooooooooooooooooooooooooong definition term' - b'this line exceeds 80 chars but should be ignored\n' - b' this is a definition\n') - fh.flush() - - parsed_file = parser.ParsedFile(fh.name, encoding='utf-8') - check = checks.CheckMaxLineLength(conf) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(0, len(errors)) - - -class TestNewlineEndOfFile(testtools.TestCase): - def test_newline(self): - tests = [(1, b"testing"), - (1, b"testing\ntesting"), - (0, b"testing\n"), - (0, b"testing\ntesting\n")] - - for expected_errors, line in tests: - with tempfile.NamedTemporaryFile() as fh: - fh.write(line) - fh.flush() - parsed_file = parser.ParsedFile(fh.name) - check = checks.CheckNewlineEndOfFile({}) - errors = list(check.report_iter(parsed_file)) - self.assertEqual(expected_errors, len(errors)) diff --git a/doc8/utils.py b/doc8/utils.py deleted file mode 100644 index d500d15..0000000 --- a/doc8/utils.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2014 Ivan Melnikov -# -# Author: Joshua Harlow -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import glob -import os - - -def find_files(paths, extensions, ignored_paths): - extensions = set(extensions) - ignored_absolute_paths = set() - for path in ignored_paths: - for expanded_path in glob.iglob(path): - expanded_path = os.path.abspath(expanded_path) - ignored_absolute_paths.add(expanded_path) - - def extension_matches(path): - _base, ext = os.path.splitext(path) - return ext in extensions - - def path_ignorable(path): - path = os.path.abspath(path) - if path in ignored_absolute_paths: - return True - last_path = None - while path != last_path: - # If we hit the root, this loop will stop since the resolution - # of "/../" is still "/" when ran through the abspath function... - last_path = path - path = os.path.abspath(os.path.join(path, os.path.pardir)) - if path in ignored_absolute_paths: - return True - return False - - for path in paths: - if os.path.isfile(path): - if extension_matches(path): - yield (path, path_ignorable(path)) - elif os.path.isdir(path): - for root, dirnames, filenames in os.walk(path): - for filename in filenames: - path = os.path.join(root, filename) - if extension_matches(path): - yield (path, path_ignorable(path)) - else: - raise IOError('Invalid path: %s' % path) - - -def filtered_traverse(document, filter_func): - for n in document.traverse(include_self=True): - if filter_func(n): - yield n - - -def contains_url(line): - return "http://" in line or "https://" in line - - -def has_any_node_type(node, node_types): - n = node - while n is not None: - if isinstance(n, node_types): - return True - n = n.parent - return False diff --git a/doc8/version.py b/doc8/version.py deleted file mode 100644 index 6e33c88..0000000 --- a/doc8/version.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (C) 2014 Yahoo! Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -try: - from pbr import version as pbr_version - _version_info = pbr_version.VersionInfo('doc8') - version_string = _version_info.version_string -except ImportError: - import pkg_resources - _version_info = pkg_resources.get_distribution('doc8') - version_string = lambda: _version_info.version diff --git a/pylintrc b/pylintrc deleted file mode 100644 index 4ec63b1..0000000 --- a/pylintrc +++ /dev/null @@ -1,31 +0,0 @@ -# The format of this file isn't really documented; just use --generate-rcfile - -[Messages Control] -# C0111: Don't require docstrings on every method -# W0511: TODOs in code comments are fine. -# W0142: *args and **kwargs are fine. -# W0622: Redefining id is fine. -disable=C0111,W0511,W0142,W0622 - -[Basic] -# Variable names can be 1 to 31 characters long, with lowercase and underscores -variable-rgx=[a-z_][a-z0-9_]{0,30}$ - -# Argument names can be 2 to 31 characters long, with lowercase and underscores -argument-rgx=[a-z_][a-z0-9_]{1,30}$ - -# Method names should be at least 3 characters long -# and be lowercased with underscores -method-rgx=([a-z_][a-z0-9_]{2,50}|setUp|tearDown)$ - -[Design] -max-public-methods=100 -min-public-methods=0 -max-args=6 - -[Variables] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -# _ is used by our localization -additional-builtins=_ diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8fcc512..0000000 --- a/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -chardet -docutils -restructuredtext-lint>=0.7 -six -stevedore diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 0f9b7a7..0000000 --- a/setup.cfg +++ /dev/null @@ -1,33 +0,0 @@ -[metadata] -name = doc8 -summary = Style checker for Sphinx (or other) RST documentation -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://launchpad.net/doc8 -classifier = - Intended Audience :: Information Technology - Intended Audience :: System Administrators - Intended Audience :: Developers - Development Status :: 4 - Beta - Topic :: Utilities - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - -[entry_points] -console_scripts = - doc8 = doc8.main:main - -[build_sphinx] -all_files = 1 -build-dir = doc/build -source-dir = doc/source - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100755 index 7363757..0000000 --- a/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 0b9685f..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -doc8 -hacking>=0.9.2,<0.10 -nose -oslosphinx -sphinx>=1.1.2,!=1.2.0,<1.3 -testtools diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 864ea24..0000000 --- a/tox.ini +++ /dev/null @@ -1,32 +0,0 @@ -[tox] -minversion = 1.6 -skipsdist = True -envlist = py35,py27,pep8 - -[testenv] -setenv = VIRTUAL_ENV={envdir} -usedevelop = True -install_command = pip install {opts} {packages} -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = nosetests {posargs} - -[testenv:pep8] -commands = flake8 {posargs} - -[testenv:pylint] -requirements = pylint==0.25.2 -commands = pylint doc8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = - doc8 -e .rst doc CONTRIBUTING.rst HACKING.rst README.rst - python setup.py build_sphinx - -[flake8] -builtins = _ -show-source = True -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build